tags:

views:

77

answers:

2

I have a problem with using System.Threading.Tasks.Parallel.ForEach. The body foreach progressBar want to update. But Invoke method sometimes freeze.

I attach the code to the form which is prograssbar and Buton.

private void button1_Click(object sender, EventArgs e)
{
    DateTime start = DateTime.Now;
    pforeach();
    Text = (DateTime.Now - start).ToString();
}


private void pforeach()
{
    int[] intArray = new int[60];
    int totalcount = intArray.Length;
    object lck = new object();
    System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
    () => 0,
    (x, loop, count) =>
    {
        int value = 0;
        System.Threading.Thread.Sleep(100);
        count++;
        value = (int)(100f / (float)totalcount * (float)count);

        Set(value);
        return count;
    },
    (x) =>
    {

    });
}

private void Set(int i)
{
    if (this.InvokeRequired)
    {
        var result = Invoke(new Action<int>(Set), i);
    }
    else
        progressBar1.Value = i;
}

Sometimes it passes without a problem, but usually it freeze on var result = Invoke (new Action <int> (Set), i). Try to kick me in the problem.

Thank you.

+1  A: 

I was looking at how I did this and this change may help you:

In my constructor I have this line:

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

Then I do this:

    private void changeProgressBar()
    {
        (new Task(() =>
        {
            mainProgressBar.Value++;
            mainProgressTextField.Text = mainProgressBar.Value + " of " + mainProgressBar.Maximum;
        })).Start(uiScheduler);
    }

This gets rid of needing to use Invoke, and if you use the Task method then it may solve your problem.

I think these were all in System.Threading.Tasks;

James Black
+2  A: 

Your problem is that Invoke (and queueing a Task to the UI TaskScheduler) both require the UI thread to be processing its message loop. However, it is not. It is still waiting for the Parallel.ForEach loop to complete. This is why you see a deadlock.

If you want the Parallel.ForEach to run without blocking the UI thread, wrap it into a Task, as such:

private TaskScheduler ui;
private void button1_Click(object sender, EventArgs e) 
{
    ui = TaskScheduler.FromCurrentSynchronizationContext();
    DateTime start = DateTime.Now;
    Task.Factory.StartNew(pforeach)
        .ContinueWith(task =>
        {
            task.Wait(); // Ensure errors are propogated to the UI thread.
            Text = (DateTime.Now - start).ToString(); 
        }, ui);
} 

private void pforeach() 
{ 
    int[] intArray = new int[60]; 
    int totalcount = intArray.Length; 
    object lck = new object(); 
    System.Threading.Tasks.Parallel.ForEach<int, int>(intArray, 
    () => 0, 
    (x, loop, count) => 
    { 
        int value = 0; 
        System.Threading.Thread.Sleep(100); 
        count++; 
        value = (int)(100f / (float)totalcount * (float)count); 

        Task.Factory.StartNew(
            () => Set(value),
            CancellationToken.None,
            TaskCreationOptions.None,
            ui).Wait();
        return count; 
    }, 
    (x) => 
    { 

    }); 
} 

private void Set(int i) 
{ 
    progressBar1.Value = i; 
} 
Stephen Cleary
Thank you it work fine.
Aik