【问题标题】:WaitHandle fundamental behaviorWaitHandle 基本行为
【发布时间】:2014-08-31 15:28:57
【问题描述】:

这两个代码块在查看控制台时是否具有相同的效果?
请注意:目前我仍在使用并绑定到 .NET 3.5。

第一:

for(int i = 0; i<3;i++)
{
    Console.WriteLine(i);
}

第二:

class Worker
{
    static int i = 0;
    static ManualResetEvent manualResetEvent = new ManualResetEvent(false);       
    static Object locky = new Object();
    static void Work(Object workItem)
    {
        WaitHandle[] wait = new [] { manualResetEvent };

        while (WaitHandle.WaitAny(wait))
        {
            lock (locky)
            {
                Console.WriteLine(i++);
            }
        }
    }
}
// main:

Thread thread = new Thread(Worker.Work);
thread.Start();

for (int i=0;i<3;i++)
{
    Worker.manualResetEvent.Set();
}

waitHandle 会随着每个信号的增加而增加吗?循环会一直运行到所有信号都完成吗? 或者当线程已经在工作时会忽略信号吗?

有人可以为这件事带来一些启示吗?

【问题讨论】:

  • 第二个代码甚至不会编译,所以不,它们没有相同的效果。一旦你得到了可以编译的代码,我建议你自己尝试一下——如果你能看到不同之处,显然有很大的不同。如果你不能,那么这是一个更合理的问题(因为它可能是一个细微的差别)。
  • ManualResetEvent,顾名思义,需要手动重置。它将一直设置到您 Reset 它 - 因此您将获得无限循环的写入行。此外,您不能锁定值类型!无论如何,请尝试使用可用的最高级别抽象。您似乎对多线程和同步的了解太低了 - 请查看 TPL、DataFlow 和类似的更友好的构造。
  • @Luaan 谢谢你正是我所缺少的。
  • 更正了原生类型的锁
  • 其实,如果你想走这条路,你真的需要学习更多。例如,ManualResetEvent(和AutoResetEvent)不是互斥体——更多等待事件的工作线程将获得相同的信号。并且ManualResetEvent.Set 是非阻塞的 - 所以你最终可能会遇到这样的情况:你已经设法调用Set 三次之前工作线程甚至注意到一次。总而言之,Semaphore 可能更适合您的用例。

标签: c# multithreading asynchronous threadpool waithandle


【解决方案1】:

由于您使用的是ManualResetEvent,因此一旦您发出事件信号,它就会一直保持信号状态,直到它被重置。也就是说设置一次或三次会产生同样的效果。

这也意味着工作人员将进入无限循环,因为事件永远不会重置。

此外,您不能锁定值类型。如果可以的话,int 将被装箱并在每次锁定它时创建一个新的 object - 这意味着您每次都会锁定一个不同的对象,从而使锁定变得无用。

【讨论】:

  • 幸运的是,较新的 C# 编译器明确禁止锁定值类型(除非手动将其装箱为 object) - 代码无法编译。
  • @Luaan Cool,我不确定编译器是否强制执行此操作。我已经更新了我的答案,声明“你不能这样做”而不是“你不应该这样做”:) 谢谢
  • ... 无休止地运行,直到 Worker.manualResetEvent.Reset() 被调用...这是我缺少的部分,正是我需要知道的。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-25
  • 2016-01-31
相关资源
最近更新 更多