【问题标题】:Condition variables in C# [closed]C# 中的条件变量
【发布时间】:2010-12-31 11:01:28
【问题描述】:

C# 中是否使用了条件变量和监视器?

谁能给我一个例子?

【问题讨论】:

标签: c# multithreading monitor


【解决方案1】:

在 .NET 中仅用于信号的条件变量的等价物是抽象的 WaitHandle 类。它的实际实现是 ManualResetEvent 和 AutoResetEvent 类。

用作监视器的条件变量需要 System.Threading.Monitor。 C# lock 语句使其非常易于使用,它确保监视器始终退出而无需显式编程 Exit() 调用。

【讨论】:

  • 请注意,如果代码抛出异常则退出监视器不一定是好事;监视器可能正在保护一个突变,以确保退出监视器时的结果是一致的;一个例外是突变仅部分完成的证据,因此您刚刚解锁了对不一致状态的访问。如果异常被捕获并且程序继续,那么你不能依赖于程序状态是一致的。
  • 非常好,我重新措辞了。谢谢。
  • 等等(请原谅双关语)。这些中的任何一个实际上是条件变量的直接等价物吗?在我的非专家眼中,它们与条件变量完全不同。事实上,我看过一个网页,它展示了如何从 Windows 内核对象(如自动重置事件)构建条件变量,这是一个非常复杂的过程,涉及多个这样的内核对象......
  • 我同意@mackenir -- 说WaitHandle 与条件变量相同会导致像stackoverflow.com/questions/18276944/… 这样的误解
  • @Pragmateek:除非您之前出于其他原因需要互斥锁,因为您可能在等待条件变为真之前对共享数据进行了更改。条件变量就像一个跨线程调用。您获得互斥体,设置输入参数,唤醒另一个线程(等待互斥体),然后使用条件变量以原子方式解除对另一个线程的阻塞并等待结果。之后,您再次持有互斥锁,以便您可以读取输出参数。
【解决方案2】:

此版本在等待信号时自动解锁 Mutex 或 ReaderWriterLockSlim,并在返回之前重新锁定它 - 这是 posix 方式。

using System.Collections.Concurrent;

namespace System.Threading.More {
    public class ConditionVariable {
        private readonly ConcurrentQueue<ManualResetEventSlim> _waitingThreads = new ConcurrentQueue<ManualResetEventSlim>();

        /// <summary>
        ///     Atomically unlocks and waits for a signal.
        ///     Then relocks the mutex before returning
        /// </summary>
        /// <param name="mutex"></param>
        public void Wait(Mutex mutex) {
            if (mutex == null) {
                throw new ArgumentNullException("mutex");
            }
            var waitHandle = new ManualResetEventSlim();
            try {
                _waitingThreads.Enqueue(waitHandle);
                mutex.ReleaseMutex();
                waitHandle.Wait();
            } finally {
                waitHandle.Dispose();
            }
            mutex.WaitOne();
        }

        public void WaitRead(ReaderWriterLockSlim readerWriterLock) {
            if (readerWriterLock == null) {
                throw new ArgumentNullException("readerWriterLock");
            }
            var waitHandle = new ManualResetEventSlim();
            try {
                _waitingThreads.Enqueue(waitHandle);
                readerWriterLock.ExitReadLock();
                waitHandle.Wait();
            } finally {
                waitHandle.Dispose();
            }
            readerWriterLock.EnterReadLock();
        }

        public void Signal() {
            ManualResetEventSlim waitHandle;
            if (_waitingThreads.TryDequeue(out waitHandle)) {
                waitHandle.Set();
            }
        }

        public void Broadcast() {
            ManualResetEventSlim waitHandle;
            while (_waitingThreads.TryDequeue(out waitHandle)) {
                waitHandle.Set();
            }
        }
    }
}

【讨论】:

    【解决方案3】:

    作为 ManualResetEvent 和朋友的替代方案,Windows 现在为条件变量提供native support。我自己没有对它进行基准测试,但利用原生 API 时,您的性能很有可能会提高。

    这是一篇代码项目文章,解释了如何从 C# 访问这个(相对较新的)构造:

    A .NET Wrapper for the Vista/Server 2008 Condition Variable

    【讨论】:

      【解决方案4】:

      您可以使用 Lock 对象作为 Monitor 类的语法糖。

      lock(someObject)
      {
          // Thread safe code here.
      }
      

      http://msdn.microsoft.com/en-us/library/c5kehkcz%28VS.80%29.aspx

      【讨论】:

      • 一点小修正,不是对象,而是关键字,拼写为小写,lock :)
      • 谢谢,工作中一直在用 VB.NET 进行开发,所以在大脑上安装了 SyncLock,刚刚删除了 Sync 部分,呵呵。
      【解决方案5】:

      System.Threading.Monitor 是一种方式(内例)

      【讨论】:

        猜你喜欢
        • 2021-12-28
        • 2021-10-25
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-13
        • 2015-07-01
        • 1970-01-01
        相关资源
        最近更新 更多