C# 如何创建一个稍微修改过的AutoResetEvent类?

C# 如何创建一个稍微修改过的AutoResetEvent类?,c#,multithreading,synchronizing,C#,Multithreading,Synchronizing,我需要一个行为与AutoResetEvent类完全相同的同步类,但有一个小的例外: 对Set()方法的调用必须释放所有等待的线程,而不仅仅是一个线程 如何构造这样一个类?我完全没有主意了 马丁 那么您有多个线程在执行一个.WaitOne(),您想释放它们吗 使用ManualResetEvent类,所有等待的线程都应该释放…两件您可以尝试的事情 使用Barrier对象有条件地添加线程并向其发送信号 另一种可能是使用RX中的发布者-订阅者设置。每个线程等待传递给集合的对象。当您想在快照上调用“se

我需要一个行为与AutoResetEvent类完全相同的同步类,但有一个小的例外:

对Set()方法的调用必须释放所有等待的线程,而不仅仅是一个线程

如何构造这样一个类?我完全没有主意了

  • 马丁

那么您有多个线程在执行一个.WaitOne(),您想释放它们吗


使用ManualResetEvent类,所有等待的线程都应该释放…

两件您可以尝试的事情

使用Barrier对象有条件地添加线程并向其发送信号

另一种可能是使用RX中的发布者-订阅者设置。每个线程等待传递给集合的对象。当您想在快照上调用“set”循环时,在每个成员上调用set


或者您可以尝试bears。

如果公共字段或属性中的所有线程都引用了该事件,则可以使用新的未发出信号的事件替换该公共字段或属性,然后向旧的事件发出信号。因为您将定期创建新的同步对象,所以它会有一些成本,但它会起作用。以下是我将如何做到这一点的示例:

public static class Example
{
    private static volatile bool stopRunning;
    private static ReleasingAutoResetEvent myEvent;

    public static void RunExample()
    {
        using (Example.myEvent = new ReleasingAutoResetEvent())
        {
            WaitCallback work = new WaitCallback(WaitThread);

            for (int i = 0; i < 5; ++i)
            {
                ThreadPool.QueueUserWorkItem(work, i.ToString());
            }

            Thread.Sleep(500);

            for (int i = 0; i < 3; ++i)
            {
                Example.myEvent.Set();
                Thread.Sleep(5000);
            }

            Example.stopRunning = true;
            Example.myEvent.Set();
        }
    }

    private static void WaitThread(object state)
    {
        while (!Example.stopRunning)
        {
            Example.myEvent.WaitOne();
            Console.WriteLine("Thread {0} is released!", state);
        }
    }
}

public sealed class ReleasingAutoResetEvent : IDisposable
{
    private volatile ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    public void Set()
    {
        ManualResetEvent eventToSet = this.manualResetEvent;
        this.manualResetEvent = new ManualResetEvent(false);
        eventToSet.Set();
        eventToSet.Dispose();
    }

    public bool WaitOne()
    {
        return this.manualResetEvent.WaitOne();
    }

    public bool WaitOne(int millisecondsTimeout)
    {
        return this.manualResetEvent.WaitOne(millisecondsTimeout);
    }

    public bool WaitOne(TimeSpan timeout)
    {
        return this.manualResetEvent.WaitOne(timeout);
    }

    public void Dispose()
    {
        this.manualResetEvent.Dispose();
    }
}
公共静态类示例
{
私有静态易失bool停止运行;
私有静态释放自动重置事件myEvent;
公共静态void运行示例()
{
使用(Example.myEvent=new ReleasingAutoResetEvent())
{
WaitCallback工作=新的WaitCallback(WaitThread);
对于(int i=0;i<5;++i)
{
QueueUserWorkItem(work,i.ToString());
}
睡眠(500);
对于(int i=0;i<3;++i)
{
例如.myEvent.Set();
睡眠(5000);
}
Example.stopRunning=true;
例如.myEvent.Set();
}
}
私有静态void WaitThread(对象状态)
{
而(!Example.stopRunning)
{
myEvent.WaitOne()示例;
WriteLine(“线程{0}已释放!”,状态);
}
}
}
公共密封类释放自动重置事件:IDisposable
{
专用易失性手动复位事件手动复位事件=新的手动复位事件(假);
公共无效集()
{
ManualResetEventToSet=此。ManualResetEvent;
this.manualResetEvent=新的manualResetEvent(假);
eventToSet.Set();
eventToSet.Dispose();
}
公共布尔韦通()
{
返回此.manualResetEvent.WaitOne();
}
公共布尔韦通(整数毫秒)
{
返回此.manualResetEvent.WaitOne(毫秒计时);
}
公用bool WaitOne(TimeSpan超时)
{
返回此.manualResetEvent.WaitOne(超时);
}
公共空间处置()
{
此.manualResetEvent.Dispose()文件;
}
}

下面是另一个使用Monitor类锁定和解锁对象的轻量级解决方案。然而,我对这个版本的ReleasingAutoResetEvent的清理故事不太满意,因为如果没有正确地处理它,监视器可能会保留对它的引用,并使它无限期地保持活动状态

此实现存在一些限制/缺陷。首先,创建此对象的线程将是唯一能够向其发出Set调用信号的线程;尝试执行相同操作的其他线程将收到SynchronizationLockException。其次,创建它的线程将永远无法成功地等待它,因为它已经拥有锁。只有当您只有一个控制线程和几个其他等待线程时,这才是一个有效的解决方案

public static class Example
{
    private static volatile bool stopRunning;
    private static ReleasingAutoResetEvent myEvent;

    public static void RunExample()
    {
        using (Example.myEvent = new ReleasingAutoResetEvent())
        {
            WaitCallback work = new WaitCallback(WaitThread);

            for (int i = 0; i < 5; ++i)
            {
                ThreadPool.QueueUserWorkItem(work, i.ToString());
            }

            Thread.Sleep(500);

            for (int i = 0; i < 3; ++i)
            {
                Example.myEvent.Set();
                Thread.Sleep(5000);
            }

            Example.stopRunning = true;
            Example.myEvent.Set();
        }
    }

    private static void WaitThread(object state)
    {
        while (!Example.stopRunning)
        {
            Example.myEvent.WaitOne();
            Console.WriteLine("Thread {0} is released!", state);
        }
    }
}

public sealed class ReleasingAutoResetEvent : IDisposable
{
    private volatile object lockObject = new object();

    public ReleasingAutoResetEvent()
    {
        Monitor.Enter(this.lockObject);
    }

    public void Set()
    {
        object objectToSignal = this.lockObject;
        object objectToLock = new object();

        Monitor.Enter(objectToLock);
        this.lockObject = objectToLock;
        Monitor.Exit(objectToSignal);
    }

    public void WaitOne()
    {
        object objectToMonitor = this.lockObject;
        Monitor.Enter(objectToMonitor);
        Monitor.Exit(objectToMonitor);
    }

    public bool WaitOne(int millisecondsTimeout)
    {
        object objectToMonitor = this.lockObject;
        bool succeeded = Monitor.TryEnter(objectToMonitor, millisecondsTimeout);

        if (succeeded)
        {
            Monitor.Exit(objectToMonitor);
        }

        return succeeded;
    }

    public bool WaitOne(TimeSpan timeout)
    {
        object objectToMonitor = this.lockObject;
        bool succeeded = Monitor.TryEnter(objectToMonitor, timeout);

        if (succeeded)
        {
            Monitor.Exit(objectToMonitor);
        }

        return succeeded;
    }

    public void Dispose()
    {
        Monitor.Exit(this.lockObject);
    }
}
公共静态类示例
{
私有静态易失bool停止运行;
私有静态释放自动重置事件myEvent;
公共静态void运行示例()
{
使用(Example.myEvent=new ReleasingAutoResetEvent())
{
WaitCallback工作=新的WaitCallback(WaitThread);
对于(int i=0;i<5;++i)
{
QueueUserWorkItem(work,i.ToString());
}
睡眠(500);
对于(int i=0;i<3;++i)
{
例如.myEvent.Set();
睡眠(5000);
}
Example.stopRunning=true;
例如.myEvent.Set();
}
}
私有静态void WaitThread(对象状态)
{
而(!Example.stopRunning)
{
myEvent.WaitOne()示例;
WriteLine(“线程{0}已释放!”,状态);
}
}
}
公共密封类释放自动重置事件:IDisposable
{
私有易失性对象lockObject=新对象();
公开发布自动重置事件()
{
Monitor.Enter(this.lockObject);
}
公共无效集()
{
object objectToSignal=this.lockObject;
objectobjecttolock=新对象();
Monitor.Enter(objectToLock);
this.lockObject=objectToLock;
监视器。退出(objectToSignal);
}
公营机构
{
object objectToMonitor=this.lockObject;
Monitor.Enter(objectToMonitor);
监视器。退出(objectToMonitor);
}
公共布尔韦通(整数毫秒)
{
object objectToMonitor=this.lockObject;
bool succeed=Monitor.TryEnter(objectToMonitor,毫秒计时);
如果(成功)
{
监视器。退出(objectToMonitor);
}
返回成功;
}
公用bool WaitOne(TimeSpan超时)
{
object objectToMonitor=this.lockObject;
bool succeed=Monitor.TryEnter(objectToMonitor,超时);
如果(成功)
{
监视器。退出(objectToMonitor);
}
返回成功;
}
公共空间处置()
{
Monitor.Exit(此.lockObject);
}
}
public sealed class Signaller
{
    public void PulseAll()
    {
        lock (_lock)
        {
            Monitor.PulseAll(_lock);
        }
    }

    public bool Wait(TimeSpan maxWaitTime)
    {
        lock (_lock)
        {
            return Monitor.Wait(_lock, maxWaitTime);
        }
    }

    private readonly object _lock = new object();
}