Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何让我的方法等待所有线程完成?_C#_Multithreading - Fatal编程技术网

C# 如何让我的方法等待所有线程完成?

C# 如何让我的方法等待所有线程完成?,c#,multithreading,C#,Multithreading,我有一个方法,就是启动线程来做一些工作。将有两个线程异步运行一段时间,当调用它们的回调方法get时,回调将触发另一个线程,直到所有工作完成。如何使我的方法等待所有这些线程完成并被触发?使用WaitHandles,每个线程都应该有一个WaitHandle,例如ManualResetEvent和when finished call Set()在事件上 main方法应该为每个线程传递句柄 IList<WaitHandle> waitHandles = new List<

我有一个方法,就是启动线程来做一些工作。将有两个线程异步运行一段时间,当调用它们的回调方法get时,回调将触发另一个线程,直到所有工作完成。如何使我的方法等待所有这些线程完成并被触发?

使用WaitHandles,每个线程都应该有一个WaitHandle,例如ManualResetEvent和when finished call Set()在事件上

main方法应该为每个线程传递句柄

        IList<WaitHandle> waitHandles = new List<WaitHandle>();
        var newThread = new Thread(new ParameterizedThreadStart((handle) =>
        {
            // thread stuff goes here

            ((ManualResetEvent)handle).Set();
        }));
        var manualResetEvent = new ManualResetEvent(false);
        waitHandles.Add(manualResetEvent);
        newThread.Start(manualResetEvent);

        // create other threads similarly

        // wait for all threads to complete - specify a timeout to prevent a deadlock if a thread fails to set the event
        WaitHandle.WaitAll(waitHandles.ToArray());
IList waitHandles=new List();
var newThread=新线程(新的参数化线程开始((句柄)=>
{
//线在这里
((ManualResetEvent)句柄).Set();
}));
var manualResetEvent=新的manualResetEvent(错误);
waitHandles.Add(手动重置事件);
newThread.Start(手动重置事件);
//类似地创建其他线程
//等待所有线程完成-如果线程未能设置事件,请指定超时以防止死锁
WaitHandle.WaitAll(waitHandles.ToArray());

在所有线程上进行简单调用
连接。因此,如果您只有两个线程变量:

thread1.Join();
thread2.Join();
或者如果你有一个收藏:

foreach (Thread thread in threads)
{
    thread.Join();
}
不管线程以什么顺序结束;只有在所有线程完成后,代码才会继续

但是,如果您一直在创建新线程,这可能没有多大帮助。。。您可能需要有一些仅在锁中访问的集合(例如队列),并让每个线程生成活动将新线程添加到队列中。。。然后迭代(小心!),直到队列为空:

while (true)
{
    Thread nextThread;
    lock (collectionLock)
    {
        if (queue.Count == 0)
        {
            break;
        }
        nextThread = queue.Dequeue();
    }
    nextThread.Join();
}

理想情况下,如果您使用的是.NET4,请尝试使用任务并行库,这样做会更容易:)

在最简单的情况下,您可以使用Join

    Threading.Thread myThread1 = new Thread(new ThreadStart(Worker1));
    Threading.Thread myThread2 = new Thread(new ThreadStart(Worker2));
    myThread1.Start();
    myThread2.Start();
    myThread1.Join();
    myThread2.Join();

在开始任何线程之前增加一个初始为零的计数器。联锁。在退出/环回之前,在每个线程中减少一个计数器。如果任何线程将计数器递减为零,则将()设置为AutoResetEvent。自动resetEvent上的WaitOne()

Rgds,
Martin

如果这是.Net 4.0,您可以使用


我正在使用线程池,如果我只是在排队等待用户工作项,我将如何执行thread.join?另外,我不能使用TPL,因为我在3.5上,无法获得4://@Joey:好吧,如果你使用的线程池会让生活更艰难。你的问题是你在“发射线程”,这不是一回事。。。写问题时总是值得注意的:)我可以很容易地将它更改为使用线程,我想我会这样做。@Joey Gfd:我用
CountdownEvent
的自定义实现更新了我的答案,我不久前为一个个人项目写的,你可以在.Net 3.5中使用。你可以很容易地在
线程池中使用它。注意到其他帖子后,我应该补充一点——不管启动了多少线程,我的解决方案都可以工作——有时编译时不知道这一点。此外,如果线程实际退出,使用Join()的解决方案应该可以正常工作-如果它们循环并等待以后做更多工作,Join()将无法工作。另一点-WaitHandle.WaitAll只能处理(!),64个句柄-这是对内部使用的WaitForMultipleObjects()API的限制,(现在可能会挑剔-我应该闭嘴:)。
WaitAll也有64个句柄的限制,所以它的可伸缩性不是很好。此外,基于监控类的倒计时事件实现-
const int threads = 10;
using( CountdownEvent evt = new CountdownEvent(threads) )
{
    for( int x = 0; x < threads; ++x )
    {
        ThreadPool.QueueUserWorkItem((state) =>
            {
                // Do work here
                ((CountdownEvent)state).Signal();
            }, evt);
    }

    evt.Wait();
}
Console.WriteLine("Everyone finished!");
/// <summary>
/// Represents a synchronization primitive that is signaled when its count reaches zero.
/// </summary>
/// <remarks>
/// <para>
///   This class is similar to but less versatile than .Net 4's built-in CountdownEvent.
/// </para>
/// </remarks>
public sealed class CountdownEvent : IDisposable
{
    private readonly ManualResetEvent _reachedZeroEvent = new ManualResetEvent(false);
    private volatile int _count;
    private volatile bool _disposed;

    /// <summary>
    /// Initializes a new instance of the <see cref="CountdownEvent"/> class.
    /// </summary>
    /// <param name="initialCount">The initial count.</param>
    public CountdownEvent(int initialCount)
    {
        _count = initialCount;
    }

    // Disable volatile not treated as volatile warning.
#pragma warning disable 420

    /// <summary>
    /// Signals the event by decrementing the count by one.
    /// </summary>
    /// <returns><see langword="true" /> if the count reached zero and the event was signalled; otherwise, <see langword="false"/>.</returns>
    public bool Signal()
    {
        CheckDisposed();

        // This is not meant to prevent _count from dropping below zero (that can still happen due to race conditions),
        // it's just a simple way to prevent the function from doing unnecessary work if the count has already reached zero.
        if( _count <= 0 )
            return true;

        if( Interlocked.Decrement(ref _count) <= 0 )
        {
            _reachedZeroEvent.Set();
            return true;
        }
        return false;
    }

#pragma warning restore 420

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set.
    /// </summary>
    public void Wait()
    {
        CheckDisposed();
        _reachedZeroEvent.WaitOne();
    }

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set, using a <see cref="TimeSpan"/> to measure the timeout.
    /// </summary>
    /// <param name="timeout">The timeout to wait, or a <see cref="TimeSpan"/> representing -1 milliseconds to wait indefinitely.</param>
    /// <returns><see langword="true"/> if the <see cref="CountdownEvent"/> was set; otherwise, <see langword="false"/>.</returns>
    public bool Wait(TimeSpan timeout)
    {
        CheckDisposed();
        return _reachedZeroEvent.WaitOne(timeout, false);
    }

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set, using a 32-bit signed integer to measure the timeout.
    /// </summary>
    /// <param name="millisecondsTimeout">The timeout to wait, or <see cref="Timeout.Infinite"/> (-1) to wait indefinitely.</param>
    /// <returns><see langword="true"/> if the <see cref="CountdownEvent"/> was set; otherwise, <see langword="false"/>.</returns>
    public bool Wait(int millisecondsTimeout)
    {
        CheckDisposed();
        return _reachedZeroEvent.WaitOne(millisecondsTimeout, false);
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if( !_disposed )
        {
            if( disposing )
                ((IDisposable)_reachedZeroEvent).Dispose();
            _disposed = true;
        }
    }

    private void CheckDisposed()
    {
        if( _disposed )
            throw new ObjectDisposedException(typeof(CountdownEvent).FullName);
    }
}