【问题标题】:c# Thread sync - AutoResetEventc# 线程同步 - AutoResetEvent
【发布时间】:2011-02-12 12:02:34
【问题描述】:

我一直在使用 AutoResetEvent 在线程之间进行同步。

  • 一些线程(A-F)调用 autoresetevent.WaitOne();在等待另一个线程 (X) 完成其工作时
  • 虽然拥有 autoresetevent 的线程 (X) 完成其工作,然后调用 .Set();

但是,只有一个等待线程 (A-F) 未被阻塞。 - 当线程(X)完成它的工作时,我怎样才能让它们全部解除阻塞?

我想我使用了错误的同步原语 - 我应该使用什么以及如何使用?

代码示例将是理想的

【问题讨论】:

  • 听起来你也想同步 A-F 线程。更多信号或 ManualResetEvent + Interlocked 计数器可能会起作用。
  • 问题是我不知道 A-F 中有多少线程,所以我不能调用 set 正确的次数
  • 您在寻找Monitor.PulseAll吗?
  • @Ani 我将如何使用 monitor.pulseAll ?会比下面提到的manualresetevent更好吗?
  • 你应该仔细考虑 ReaderWriterLockSlim

标签: c# .net multithreading


【解决方案1】:

ManualResetEvent 是您要找的吗?

它将保持设置,直到被某个线程重置。

在您的代码中的某个地方,您必须知道何时重置它。这可能是一个简单的计数器或衍生线程的集合。

【讨论】:

  • 啊哈!听起来不错! “当控制线程完成活动时,它调用 Set 来表示等待线程可以继续。所有等待线程都被释放。”我试试看!
  • 是的,明白了 :) 不知道为什么选择手动和自动名称,它们的描述性不是很好
  • :) 自动自动重置,手动需要显式或手动操作才能设置事件。我很高兴它成功了。
  • 此链接中有一个更好的 ManualResetEvent 示例/描述:stackoverflow.com/a/3228242/1507899
【解决方案2】:

假设你有这个代码:

class Program
{
    static void Main(string[] args)
    {
        var are = new AutoResetEvent(false);

        for (int i = 0; i < 10; i++)
        {
            var j = i;
            new Thread(() =>
            {
                Console.WriteLine("Started {0}", j);
                are.WaitOne();
                Console.WriteLine("Continued {0}", j); 
            }).Start();
        }

        are.Set();

        Console.ReadLine();
    }
}

然后你会得到这样的输出:

Started 0
Started 1
Started 2
Started 3
Started 4
Started 5
Started 6
Started 7
Started 8
Continued 0
Started 9

但如果你改为使用ManualResetEvent:

class Program
{
    static void Main(string[] args)
    {
        var mre = new ManualResetEvent(false);

        for (int i = 0; i < 10; i++)
        {
            var j = i;
            new Thread(() =>
            {
                Console.WriteLine("Started {0}", j);
                mre.WaitOne();
                Console.WriteLine("Continued {0}", j); 
            }).Start();
        }

        mre.Set();

        Console.ReadLine();
    }
}

然后你会得到我猜是预期的行为:

Started 0
Started 1
Started 2
Started 3
Started 4
Started 5
Started 6
Started 7
Started 8
Started 9
Continued 1
Continued 8
Continued 7
Continued 4
Continued 5
Continued 6
Continued 3
Continued 0
Continued 9
Continued 2

当然,顾名思义,ManualResetEvent 需要手动重置,而 AutoResetEvent自动在第一个 WaitOne 释放其线程后重置.

【讨论】:

  • 感谢代码示例 (+1),这是我遇到的问题和解决方案。接受 Emo 作为第一。还是不明白这两个类的名字!
  • 请注意,Markus Johnsson 没有调用 mre.Reset()(进行手动重置)。你可能想这样做。
【解决方案3】:

使用 System.Threading.ManualResetEvent。

线程 A-F 调用 mre.WaitOne() 以等待线程 (X)。

当线程 X 完成时,调用 mre.Set() 将唤醒线程 A-F。

在线程 X 中,通过执行 mre.Reset() 将您的 mre 重置为基本状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多