Индикатор выполнения в параллельном вызове цикла
Я пытаюсь обновить индикатор выполнения в многопоточной среде. Я знаю, что многие вопросы уже относятся к этому вопросу, но ни одно из предложенных решений не помогло мне. Вот основа моего кода:
public static void DO_Computation(//parameters) {
//Intialisation of parameters
Parallel.For(struct initialisation with local data) {
//business logic
//Call to update_progressbar (located in an another class, as the DO_Computation function is in Computation.cs class (not deriving from Form).
WinForm.Invoke((Action)delegate {Update_Progress_Bar(i);}); //WinForm is a class that exposes the progressbar.
}
}
Это не работает (индикатор прогресса останавливается при достижении 100%, что является нормальным (мы можем обратиться кстатья о майкрософт в этом вопросе (действительно, это не потокобезопасный метод работы)). Сайт Microsoft предусматривает обернутьParallel.For
петля вTask
рутина следующим образом:
public static void DO_Computation(//parameters) {
//Intialisation of parameters
Task.Factory.StartNew(() =>
{
Parallel.For(struct initialosation with local data) {
//business logic
//Call to update_progressbar (ocated in an another class, as the DO_Computation function is in Computation.cs class (not deriving from Form).
WinForm.Invoke((Action)delegate {Update_Progress_Bar(i);}); //WinForm is a class that exposes the progressbar.
..
}
});
});
Однако это также не работает, когда отладка потока выходит непосредственно из области задач.
РЕДАКТИРОВАТЬ 2:
По сути, моя проблема делится на 3 части:Computation.cs
(гдеDO_Computation
разоблачен),WinForm
это форма, содержащая индикатор выполнения, иMainWindow
это форма, содержащая кнопку, которая при нажатии открывает форму с индикатором выполнения.
Я не совсем понимаю, что толку от «Задачи» в этом случае. Потому что он выходит за рамки задачи, не выполняя никакихParallel.For
Работа
Есть идеи?
Большое спасибо,
РЕДАКТИРОВАТЬ 3:
Я обновил свой код с помощью Noseratio (ему большое спасибо). Однако у меня та же проблема, что код внутри задачи никогда не выполняется. Мой код теперь выглядит так:
DoComputation method
//Some Initilasations here
Action enableUI = () =>
{
frmWinProg.SetProgressText("Grading Transaction...");
frmWinProg.ChangeVisibleIteration(true);
};
Action<Exception> handleError = (ex) =>
{
// error reporting
MessageBox.Show(ex.Message);
};
var cts = new CancellationTokenSource();
var token = cts.Token;
Action cancel_work = () =>
{
frmWinProg.CancelTransaction();
cts.Cancel();
};
var syncConext = SynchronizationContext.Current;
Action<int> progressReport = (i) =>
syncConext.Post(_ => frmWinProg.SetIteration(i,GrpModel2F.NumOfSim, true), null);
var task = Task.Factory.StartNew(() =>
{
ParallelLoopResult res = Parallel.For<LocalDataStruct>(1,NbSim, options,
() => new DataStruct(//Hold LocalData for each thread),
(iSim, loopState, DataStruct) =>
//Business Logic
if (token.IsCancellationRequested)
{
loopState.Stop();
}
progressReport(iSim);
//Business Logic
return DataStruct;
},
(DataStruct) =>
//Assiginig Results;
});//Parallel.For end
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
task.ContinueWith(_ =>
{
try
{
task.Wait();
}
catch (Exception ex)
{
while (ex is AggregateException && ex.InnerException != null)
ex = ex.InnerException;
handleError(ex);
}
enableUI();
}, TaskScheduler.FromCurrentSynchronizationContext
());
Обратите внимание, что функция Do_Computation сама вызывается из формы, в которой запускается BackGroundWorker.