2

我研究过,在并发编程中有一种叫做“事件信号量”的东西,它的工作原理是这样的:

假设“ sem”是事件信号量对象。

正在执行的线程sem.Wait()被挂起,直到有人调用sem.signalAll()唤醒任何等待 sem 的线程。

我在 C# 中找不到这样的东西。http://msdn.microsoft.com/it-it/library/system.threading.semaphore.aspxSemaphore类是我所说的计数信号量,并不是我所需要的。http://msdn.microsoft.com/it-it/library/system.threading.manualreseteventslim.aspx更接近,我认为我可以通过调用folowerd来实现我的目标,但我已经读过它并不意味着要使用像那样,它可能不会唤醒所有等待的线程。ManualResetEventSlim set();reset();

PS,我不知道我有多少等待线程,我想我可以数一数,但我更喜欢类似signalAll().

4

2 回答 2

2

没有内置任何内容,但您可以使用Monitor. 如果您封装逻辑(这并不完全明显),这是最简单的:

public sealed class Signaller
{
    public void PulseAll()
    {
        lock (_lock)
        {
            Monitor.PulseAll(_lock);
        }
    }

    public void Wait()
    {
        Wait(Timeout.Infinite);
    }

    public bool Wait(int timeoutMilliseconds)
    {
        lock (_lock)
        {
            return Monitor.Wait(_lock, timeoutMilliseconds);
        }
    }

    private readonly object _lock = new object();
}

使用它的示例代码:

public static class Program
{
    private static void Main(string[] args)
    {
        _startCounter = new CountdownEvent(NUM_THREADS);

        for (int i = 0; i < NUM_THREADS; ++i)
        {
            int id = i;
            Task.Factory.StartNew(() => test(id));
        }

        Console.WriteLine("Waiting for " + NUM_THREADS + " threads to start");
        _startCounter.Wait(); // Wait for all threads to have started.
        Thread.Sleep(100);
        Console.WriteLine("Threads all started. Setting signal now.");
        _signal.PulseAll();
        Thread.Sleep(1000);
        Console.WriteLine("\n{0}/{1} threads received the signal.\n\n", _signalledCount, NUM_THREADS);
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void test(int id)
    {
        _startCounter.Signal(); // Used so main thread knows when all threads have started.
        _signal.Wait();
        Interlocked.Increment(ref _signalledCount);
        Console.WriteLine("Task " + id + " received the signal.");
    }

    private const int NUM_THREADS = 20;

    private static readonly Signaller _signal = new Signaller();
    private static CountdownEvent _startCounter;
    private static int _signalledCount;
}

另请参阅此线程:Is there a .Net class to do what ManualResetEvent.PulseAll() would do (如果它存在)?

于 2013-08-23T14:17:35.567 回答
2

调用or将唤醒所有等待Set的线程,前提是您在调用 后不要过早调用它。ManualResetEventManualResetEventSlimResetSet

其他可能性,取决于你想要做什么,是BarrierCountdownEvent,以及MonitorMatthew Wilson 在他的回答中解释得很好。

于 2013-08-23T14:34:52.290 回答