对于许多线程中的循环

时间:2011-05-06 14:44:36

标签: c# multithreading .net-3.5 loops thread-safety

如何在另一个线程中运行每个for循环调用,但是ExternalMethod的延续应该等到for循环的最后一个工作线程的结束(和同步)?

ExternalMethod()
{
    //some calculations
    for (int i = 0; i < 10; i++)
    {
        SomeMethod(i);
    }
    //continuation ExternalMethod
}

4 个答案:

答案 0 :(得分:5)

一种方法是使用ManualResetEvent

考虑以下代码(请注意,这不应该作为一个工作示例,卡在OSX上,所以没有VS或C#编译器可以检查这个):

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

重要 - 这可能不是最佳方式,只是使用ManualResetEvent的一个示例,它将完全适合您的需求。

如果您使用的是.NET 4.0,则可以使用Parallel.For循环 - explained here

答案 1 :(得分:4)

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

答案 2 :(得分:1)

一种方法是使用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
}

如果CountdownEvent不可用,则此处是另一种方法。

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
}

请注意,在这两个示例中,for循环本身被视为并行工作项(它与其他工作项完全相同),以避免在第一个工作项可能出现的非常微妙的竞争条件工作项在下一个工作项排队之前发出事件信号。

答案 3 :(得分:0)

对于.NET 3.5,可能是这样的:

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();

使用Join()方法似乎违反直觉,但由于您实际上在执行WaitAll类型模式,因此连接的执行顺序无关紧要。