是否有一个.NET类做ManualResetEvent.PulseAll()会做什么(如果它存在)? [英] Is there a .Net class to do what ManualResetEvent.PulseAll() would do (if it existed)?

查看:110
本文介绍了是否有一个.NET类做ManualResetEvent.PulseAll()会做什么(如果它存在)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个.NET类的事 ManualResetEvent.PulseAll()会做(如果存在)?



我有一个需要原子方式释放一组正在等待同一信号的线程。 (我并不担心线程踩踏我的预期用途。)



您不能使用的ManualResetEvent 去做这个。例如,如果你这样做:

  ManualResetEventSlim信号=新ManualResetEventSlim(); 
// ...
signal.Set();
signal.Reset();



然后没有线程等待的信号的是在全部释放。



如果你把一个 Thread.sleep代码(5)设置() $ C>和重置()通话,然后一些,但的的所有等待的线程都被释放。睡眠增加为10ms允许释放所有线程。 (这是与20个线程的测试。)



显然,这是不可接受的被加入 Thread.sleep代码()来使这项工作。



不过,这是很容易做到与 Monitor.PulseAll做(),我已经写了一个微小的类来这样做。
(我写了一个类来做到这一点的原因是,我们已经发现,使用监视器逻辑,而相当简单,就足以不明显,使其值得拥有这样一个类来简化使用。)



我的问题很简单:是否有类已经在.NET中做到这一点。



有关的参考? ,这里是我的 ManualResetEvent.PulseAll()相当于裸机版本:

 公共密封类信号装置
{
公共无效PulseAll()
{
锁(_lock)
{
Monitor.PulseAll(_lock );
}
}

公共无效等待()
{
等待(Timeout.Infinite);
}

公共BOOL等待(INT timeoutMilliseconds)
{
锁(_lock)
{
返回Monitor.Wait(_lock,timeoutMilliseconds );
}
}

私人只读对象_lock =新的对象();
}






下面是一个示例程序表明,如果不设置(睡眠之间)和reset()没有等待的线程被释放:

 使用系统; 
使用的System.Threading;使用System.Threading.Tasks
;

命名空间演示
{
公共静态类节目
{
私有静态无效的主要(字串[] args)
{
_startCounter =新CountdownEvent(NUM_THREADS);

的for(int i = 0; I< NUM_THREADS ++ I)
{
INT ID = I;
Task.Factory.StartNew(()=>试验(ID));
}

Console.WriteLine(等待+ NUM_THREADS +线程启动);
_startCounter.Wait(); //等待所有线程已经开始。
Thread.sleep代码(100);
Console.WriteLine(线程都开始设置现在的信号。);
_signal.Set();
// Thread.sleep代码(5); //由于没有睡在所有,任何线程接收信号。试试这个评论线路输出。
_signal.Reset();
Thread.sleep代码(1000);
Console.WriteLine(\\\
{0} / {1}线程收到signal.\\\
\\\
,_signalledCount,NUM_THREADS);
Console.WriteLine(按任意键退出。);
Console.ReadKey();
}

私有静态无效测试(INT ID)
{
_startCounter.Signal();当所有线程都开始//使用,因此主线程知道。
_signal.Wait();
Interlocked.Increment(REF _signalledCount);
Console.WriteLine(任务+编号+接收的信号。);
}

私人const int的NUM_THREADS = 20;

私人静态只读ManualResetEventSlim _signal =新ManualResetEventSlim();
私有静态CountdownEvent _startCounter;
私有静态诠释_signalledCount;
}
}


解决方案

您可以使用壁垒对象。它允许任务数目不详跑,然后等待其他所有到达该点



和您可以使用它的在进入类似WaitGroup方式的,如果你不知道哪些任务从哪个代码块将开始作为工作的具体工作单位。


Is there a .Net class to do what ManualResetEvent.PulseAll() would do (if it existed)?

I have a need to atomically release a set of threads that are waiting on the same signal. (I'm not worried about "thread stampedes" for my intended usage.)

You cannot use a ManualResetEvent to do this. For example, if you do:

ManualResetEventSlim signal = new ManualResetEventSlim();
// ...
signal.Set();
signal.Reset();

Then no threads waiting on signal are released at all.

If you put a Thread.Sleep(5) between the Set() and Reset() calls, then some but not all of the waiting threads all are released. Increasing the sleep to 10ms allows all the threads to be released. (This was tested with 20 threads.)

Clearly it is unacceptable to be adding Thread.Sleep() to make this work.

However, this is easy enough to do with Monitor.PulseAll() and I've written a tiny class to do so. (The reason I've written a class to do this is that we've found that the logic using Monitor, while fairly simple, is non-obvious enough to make it worth having such a class to simplify usage.)

My question is simply this: Is there a class already in .Net to do this?

For reference, here's the bare-bones version of my "ManualResetEvent.PulseAll()" equivalent:

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


Here's a sample program that demonstrates that no waiting threads are released if you don't sleep between Set() and Reset():

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    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.Set();
            // Thread.Sleep(5); // With no sleep at all, NO threads receive the signal. Try commenting this line out.
            _signal.Reset();
            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 ManualResetEventSlim _signal = new ManualResetEventSlim();
        private static CountdownEvent _startCounter;
        private static int _signalledCount;
    }
}

解决方案

You can use a Barrier object. It allows an unspecified number of Tasks to run, then wait for all others to reach that point.

And you can use it in a way similar to WaitGroup in Go if you do not know which tasks from which code blocks will start to work as a specific unit of work.

这篇关于是否有一个.NET类做ManualResetEvent.PulseAll()会做什么(如果它存在)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆