许多线程中的 for 循环

本文关键字:for 循环 多线程 | 更新日期: 2023-09-27 17:55:23

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

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

许多线程中的 for 循环

一种方法是使用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 循环 - 在此处进行了说明。

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

一种方法是使用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 循环本身都被视为并行工作项(毕竟它与其他工作项位于不同的线程上),以避免在第一个工作项在下一个工作项排队之前发出事件信号时可能发生的非常微妙的争用条件。

对于 .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-类型的模式,因此执行连接的顺序无关紧要。