开发者

For loop in many threads

How can I run each call for loop in another thread, but continuation of ExternalMethod should wait to ending of last working thread from for loop (and synchronize) ?

ExternalMethod()
{
    //some calculati开发者_如何学Goons
    for (int i = 0; i < 10; i++)
    {
        SomeMethod(i);
    }
    //continuation ExternalMethod
}


One approach would be to use a ManualResetEvent.

Consider the following code (note that this should not be taken as a working example, stuck on OSX so don't have VS nor a C# compiler to hand to check this over):

static ManualResetEvent mre = new ManualResetEvent(false);
static int DoneCount = 0;
static int DoneRequired = 9;
void ExternalMethod() {
        mre.Reset();
        for (int i = 0; i < 10; i++) {
                new Thread(new ThreadStart(ThreadVoid)).Start();
        }
        mre.WaitOne();
}

void ThreadVoid() {
        Interlocked.Increment(ref DoneCount);   

        if (DoneCount == DoneRequired) {
                mre.Set();
        }
}

IMPORTANT - This possibly isn't the best way to do it, just an example of using ManualResetEvent, and it will suit your needs perfectly fine.

If you're on .NET 4.0 you can use a Parallel.For loop - explained here.


System.Threading.Tasks.Parallel.For(0, 10, (i) => SomeMethod(i));


One approach is to use a CountdownEvent.

ExternalMethod()
{
    //some calculations
    var finished = new CountdownEvent(1);
    for (int i = 0; i < 10; i++)
    {
        int capture = i; // This is needed to capture the loop variable correctly.
        finished.AddCount();
        ThreadPool.QueueUserWorkItem(
          (state) =>
          {
            try
            {
              SomeMethod(capture);
            }
            finally
            {
              finished.Signal();
            }
          }, null);
    }
    finished.Signal();
    finished.Wait();
    //continuation ExternalMethod
}

If CountdownEvent is not available then here is an alternate approach.

ExternalMethod()
{
    //some calculations
    var finished = new ManualResetEvent(false);
    int pending = 1;
    for (int i = 0; i < 10; i++)
    {
        int capture = i; // This is needed to capture the loop variable correctly.
        Interlocked.Increment(ref pending);
        ThreadPool.QueueUserWorkItem(
          (state) =>
          {
            try
            {
              SomeMethod(capture);
            }
            finally
            {
              if (Interlocked.Decrement(ref pending) == 0) finished.Set();
            }
          }, null);
    }
    if (Interlocked.Decrement(ref pending) == 0) finished.Set();
    finished.WaitOne();
    //continuation ExternalMethod
}

Note that in both examples the for loop itself is treating as a parallel work item (it is on a separate thread from the other work items afterall) to avoid a really subtle race condition that might occur if the first work item signals the event before the next work item is queued.


For .NET 3.5, maybe something like this:

Thread[] threads = new Thread[10];

for (int x = 0; x < 10; x++)
{
    threads[x] = new Thread(new ParameterizedThreadStart(ThreadFun));
    threads[x].Start(x);
}

foreach (Thread thread in threads) thread.Join();

It may seem counterintuitive to use the Join() method, but since you are effectively doing a WaitAll-type pattern, it doesn't matter what order the joins are executed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜