8
\$\begingroup\$

I'm using a StaTaskScheduler (TPL extension) to open some web browser windows simultaneously and navigate to different sites (using WatiN, but it might as well just be a WebBrowser).

In my example below I'm running 5 concurrent browsers. Works fine, but it locked the UI thread, so I wrapped my tasks in a BackgroundWorker. Seems like it does the job, but is it the correct way of handling the issue? Do I need to dispose the worker once I'm done? And finally, is lock (ret) the correct way of keeping ret thread safe?

StaTaskScheduler sta = new StaTaskScheduler(5);
BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += (s, ea) =>
{
    List<string> ret = new List<string>();

    lock (ret)

    Task.WaitAll(Util.GetList().Select(row => Task.Factory.StartNew(() =>
    {

        IEnumerable<string> result = DoUiLockingWork(row.Item1, row.Item2);
        ret.AddRange(result);

    }, CancellationToken.None, TaskCreationOptions.None, sta)).ToArray());

    ea.Result = ret;
};

bw.RunWorkerCompleted += (s, ea) =>
{
    List<string> result = ea.Result as List<string>;

    if (result != null) 
        Debug.WriteLine(result.Count);
};

bw.RunWorkerAsync();
\$\endgroup\$
0

2 Answers 2

9
\$\begingroup\$

I would go with Task-based method (if you're using .Net 4.5) instead of the BackgroundWorker. That will sort out most of your problems.

Something in the vicinities of

async Task<List<T>> yourJobAsync(...)
{
    var results = await Task.Run ( () =>
    {
        //your job.
        return jobResults
    });
    return  yourJobAsyncResults
}
\$\endgroup\$
2
  • \$\begingroup\$ Thanks, I actually changed the approach to your suggestion once I noticed that backgroundworkers were obselete. Can this return a result from all the nested tasks, without using lock? \$\endgroup\$
    – Johan
    Commented Jun 13, 2014 at 7:41
  • 1
    \$\begingroup\$ Yes it can. You must have found out the answer by now but in general Task<T> would return a T. If you use IEnumrable<T>` instead of the List you should be able to use Yield() to return the task result. Check this Microsoft post about yield return and the example. blogs.msdn.com/b/pfxteam/archive/2008/07/23/8768673.aspx \$\endgroup\$
    – Mehrad
    Commented Jun 17, 2014 at 23:33
4
\$\begingroup\$

I would make your lock a little more tight:

lock (ret)
{
    ret.AddRange(result);
}

But otherwise, looks like an all right implementation.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thanks for the input. I also replaced the backgroundworker implementation with a pure Task solution. \$\endgroup\$
    – Johan
    Commented Jun 12, 2014 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.