Parallel call lane

I am trying to update a progress indicator in a multi-threaded environment. I know that many issues are already considering this issue, but none of the proposed solutions worked for me. Here is the basis of my code:

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. } } 

It doesn’t work (the progress indicator freezes when it reaches 100%, which is normal (we can refer to the Microsoft article in this (indeed, this is not a thread-safe method of work)) Microsoft builds the site to wrap the Parallel.For loop in the Task procedure as follows :

 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. .. } }); }); 

However, this does not work when debugging a thread directly leaves the task pane.

EDIT 2:

Basically, my problem is divided into 3 parts: Computation.cs (where DO_Computation displayed), WinForm , which is a form containing a progress bar, and MainWindow , which is a form that contains a button, which, when clicked, opens a form with a progress bar.

I do not understand what the "Task" is in this case. Because it leaves the Task area without executing Parallel.For work

Any ideas?

Thank you very much,

EDIT 3:

I updated my code with Noseratio (for him, this is a lot). However, I have the same problem as the internal code task is never executed. Now my code looks like this:

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 

());

Note that the Do_Comput function itself is called from the form on which BackGroundWorker works.

+6
source share
1 answer

Use async/await , Progress<T> and observe cancellation with CancellationTokenSource .

Good reading related: "Async in 4.5: Enabling progress and revocation in the Async API . "

If you need to configure .NET 4.0, but work with VS2012 +, you can still use async/await , Microsoft provides Microsoft.Bcl.Async libraries for this.

I put together a WinForms example that illustrates all of the above. It also shows how to observe the cancellation for the Parallel.For loop using ParallelLoopState.Stop() :

 using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication_22487698 { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } IEnumerable<int> _data = Enumerable.Range(1, 100); Action _cancelWork; private void DoWorkItem( int[] data, int item, CancellationToken token, IProgress<int> progressReport, ParallelLoopState loopState) { // observe cancellation if (token.IsCancellationRequested) { loopState.Stop(); return; } // simulate a work item Thread.Sleep(500); // update progress progressReport.Report(item); } private async void startButton_Click(object sender, EventArgs e) { // update the UI this.startButton.Enabled = false; this.stopButton.Enabled = true; try { // prepare to handle cancellation var cts = new CancellationTokenSource(); var token = cts.Token; this._cancelWork = () => { this.stopButton.Enabled = false; cts.Cancel(); }; var data = _data.ToArray(); var total = data.Length; // prepare the progress updates this.progressBar.Value = 0; this.progressBar.Minimum = 0; this.progressBar.Maximum = total; var progressReport = new Progress<int>((i) => { this.progressBar.Increment(1); }); // offload Parallel.For from the UI thread // as a long-running operation await Task.Factory.StartNew(() => { Parallel.For(0, total, (item, loopState) => DoWorkItem(data, item, token, progressReport, loopState)); // observe cancellation token.ThrowIfCancellationRequested(); }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } catch (Exception ex) { MessageBox.Show(ex.Message); } // update the UI this.startButton.Enabled = true; this.stopButton.Enabled = false; this._cancelWork = null; } private void stopButton_Click(object sender, EventArgs e) { if (this._cancelWork != null) this._cancelWork(); } } } 

Updated , here's how to do the same without async/await :

 using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication_22487698 { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } IEnumerable<int> _data = Enumerable.Range(1, 100); Action _cancelWork; private void DoWorkItem( int[] data, int item, CancellationToken token, Action<int> progressReport, ParallelLoopState loopState) { // observe cancellation if (token.IsCancellationRequested) { loopState.Stop(); return; } // simulate a work item Thread.Sleep(500); // update progress progressReport(item); } private void startButton_Click(object sender, EventArgs e) { // update the UI this.startButton.Enabled = false; this.stopButton.Enabled = true; Action enableUI = () => { // update the UI this.startButton.Enabled = true; this.stopButton.Enabled = false; this._cancelWork = null; }; Action<Exception> handleError = (ex) => { // error reporting MessageBox.Show(ex.Message); }; try { // prepare to handle cancellation var cts = new CancellationTokenSource(); var token = cts.Token; this._cancelWork = () => { this.stopButton.Enabled = false; cts.Cancel(); }; var data = _data.ToArray(); var total = data.Length; // prepare the progress updates this.progressBar.Value = 0; this.progressBar.Minimum = 0; this.progressBar.Maximum = total; var syncConext = SynchronizationContext.Current; Action<int> progressReport = (i) => syncConext.Post(_ => this.progressBar.Increment(1), null); // offload Parallel.For from the UI thread // as a long-running operation var task = Task.Factory.StartNew(() => { Parallel.For(0, total, (item, loopState) => DoWorkItem(data, item, token, progressReport, loopState)); // observe cancellation token.ThrowIfCancellationRequested(); }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); task.ContinueWith(_ => { try { task.Wait(); // rethrow any error } catch (Exception ex) { while (ex is AggregateException && ex.InnerException != null) ex = ex.InnerException; handleError(ex); } enableUI(); }, TaskScheduler.FromCurrentSynchronizationContext()); } catch (Exception ex) { handleError(ex); enableUI(); } } private void stopButton_Click(object sender, EventArgs e) { if (this._cancelWork != null) this._cancelWork(); } } } 
+7
source

All Articles