我的应用程序产生了大量不同的小工作线程,通过ThreadPool.QueueUserWorkItem它我可以通过多个ManualResetEvent实例跟踪.我使用该WaitHandle.WaitAll方法阻止我的应用程序关闭,直到这些线程完成.
但是,之前我从未遇到过任何问题,因为我的应用程序正在承受更多负载,即创建更多线程,我现在开始得到这个异常:
WaitHandles must be less than or equal to 64 - missing documentation
什么是最好的替代解决方案?
代码片段
List<AutoResetEvent> events = new List<AutoResetEvent>();
// multiple instances of...
var evt = new AutoResetEvent(false);
events.Add(evt);
ThreadPool.QueueUserWorkItem(delegate
{
// do work
evt.Set();
});
...
WaitHandle.WaitAll(events.ToArray());
Run Code Online (Sandbox Code Playgroud)
解决方法
int threadCount = 0;
ManualResetEvent finished = new ManualResetEvent(false);
...
Interlocked.Increment(ref threadCount);
ThreadPool.QueueUserWorkItem(delegate
{
try
{
// do work
}
finally
{
if (Interlocked.Decrement(ref threadCount) == 0)
{
finished.Set();
}
}
});
... …Run Code Online (Sandbox Code Playgroud) 我有一个WaitHandle,我想知道如何检查WaitHandle是否已经设置.
注意:我可以添加bool变量,每当使用Set()方法时,将变量设置为true,但必须在WaitHandle中的某处构建此行为.
感谢帮助!
我有一个EventWaitHandle我创建然后关闭的.当我尝试使用此ctor重新创建它时,会抛出"访问路径...被拒绝"异常.这个例外是罕见的,大多数时候它只是重新创建EventWaitHandle就好了.下面的答案(由我发布),我能够成功地打电话EventWaitHandle.OpenExisting并继续,如果抛出异常,但是,EventWaitHandle应该为我做这个,对吗?这不是什么out参数,createdNew是为了什么?
我在同一台服务器上有以下架构,Windows服务和Web服务.Web服务通过打开和设置Windows服务正在等待的等待句柄告诉Windows服务它必须工作.
通常一切都完美无瑕,我能够启动/停止Windows服务,而不会出现任何问题.但是,有时当我停止Web服务然后再次启动它时,它将完全无法创建等待句柄,从而破坏了整个架构.
我特别需要找出什么是破坏事件等待句柄并停止它.当等待句柄"中断"时,我必须重新启动窗口才能再次正常运行,这显然不太理想.
我重新启动Windows服务,而Web服务正在工作,希望导致问题,它做到了!一些班级名称已经因公司匿名而受到审查
12:00:41,250 [7] - Stopping execution due to a ThreadAbortException
System.Threading.ThreadAbortException: Thread was being aborted.
at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
at OurCompany.OurProduct.MyClass.MyClassCore.MonitorRequests()
12:00:41,328 [7] - Closing Event Wait Handle
12:00:41,328 [7] - Finally block reached
12:00:42,781 [6] - Application Start
12:00:43,031 [6] - Creating EventWaitHandle: Global\OurCompany.OurProduct.MyClass.EventWaitHandle
12:00:43,031 [6] - Creating EventWaitHandle with the security entity name of : Everyone
12:00:43,078 [6] …Run Code Online (Sandbox Code Playgroud) 我一直在阅读.NET Threading,并正在研究一些使用ManualResetEvent的代码.我在互联网上找到了很多代码示例.但是,在阅读WaitHandle的文档时,我看到以下内容:
WaitHandle实现了Dispose模式.请参阅实现Finalize和Dispose以清理非托管资源.
没有任何样本似乎在他们创建的ManualResetEvent对象上调用.Close(),甚至是来自pfxteam博客的好的Recursion and Concurrency文章(编辑 - 这有一个我错过的使用块).这只是示例疏忽,还是不需要?我很好奇,因为WaitHandle"封装了特定于操作系统的对象",因此很容易出现资源泄漏.
Thread.Sleep(timeout)和resetEvent.Wait(timeout)都会导致执行暂停至少timeout几毫秒,那么它们之间是否存在差异?我知道Thread.Sleep导致线程放弃其时间片的剩余部分,因此可能导致睡眠持续时间远远超过要求的时间.ManualResetEvent对象的Wait(timeout)方法是否具有相同的问题?
编辑:我知道一个ManualResetEvent的主要要点是从另一个线程发出信号 - 现在我只关注事件的Wait方法的情况,指定了超时,没有其他调用者设置事件.我想知道是否比Thread.Sleep更准确地唤醒准时
下面是一个具有'SomeMethod'方法的类,它说明了我的问题.
class SomeClass
{
AutoResetEvent theEvent = new AutoResetEvent(false);
// more member declarations
public void SomeMethod()
{
// some code
theEvent.WaitOne();
// more code
}
}
Run Code Online (Sandbox Code Playgroud)
该方法设计为线程安全的,并将在不同的线程中调用.现在我的问题是如何在任何时间点取消阻止在'theEvent'对象上调用'WaitOne'方法的所有线程?这个要求经常出现在我的设计中,因为我需要能够优雅地停止和启动我的多线程程序.在我看来,启动一个多线程程序相当简单,但很难阻止它.
这是我迄今为止尝试过的,显然有效.但这是标准方法吗?
public void UnblockAll()
{
do
{
theEvent.Set();
} while (theEvent.WaitOne(0));
}
Run Code Online (Sandbox Code Playgroud)
'UnblockAll'方法是'SomeClass'类的成员.此处使用的技术基于WaitOne方法的MSDN文档.我引用下面文档的相关部分:
如果millisecondsTimeout为零,则该方法不会阻止.它测试等待句柄的状态并立即返回.
在do..while循环中,我调用Set方法.这释放了一个可能由于调用WaitOne方法而被阻塞的线程(在'SomeMethod'方法中编码).接下来,我测试'theEvent'对象的状态,只是为了知道它是否有信号.此测试是通过调用带有超时参数的WaitOne方法的重载版本来完成的.我在调用WaitOne方法时使用的参数为零,根据文档结果,调用立即返回一个布尔值.如果返回值是true,那么"theEvent"的对象是信号状态中.如果在'SomeMethod'方法中对'WaitOne'方法的调用至少阻塞了一个线程,则调用'Set'方法(在'UnblockAll'方法中编码)将解除阻塞.因此,在'UnblockAll'方法中do..while语句结束时对'WaitOne'方法的调用将返回false.仅当没有线程被阻止时,返回值才为真.
上述推理是否正确,如果是正确的,该技术是否是处理我的问题的标准方法?我试图主要在.net compact-framework 2.0平台上使用该解决方案.
我正在尝试使用互斥锁来保护从多个线程访问某些硬件,但我对exitContext参数的含义/ 做法感到困惑:
public virtual bool WaitOne (
int millisecondsTimeout,
bool exitContext
)
Run Code Online (Sandbox Code Playgroud)
文档说:
exitContext - 如果在等待之前退出上下文的同步域(如果在同步上下文中),则返回true,然后重新获取它; 否则,错误.
......但这究竟意味着什么,将它设置为真或假的后果是什么?我现在已经把它设置为真,代码似乎有效,但我很紧张,我不完全明白它是什么由引擎盖引起的!
我想知道:锁定只允许1个线程进入代码区域
等待句柄用于发信号:
信令是指一个线程等待它收到另一个线程的通知.
所以我心想,这可以用来取代锁吗?
就像是 :
Thread number 1 --please enter ( autoreset --> autlock)
dowork...
finish work...
set signal to invite the next thread
Run Code Online (Sandbox Code Playgroud)
所以我写了这个:
/*1*/ static EventWaitHandle _waitHandle = new AutoResetEvent(true);
/*2*/
/*3*/ volatile int i = 0;
/*4*/ void Main()
/*5*/ {
/*6*/
/*7*/ for (int k = 0; k < 10; k++)
/*8*/ {
/*9*/ var g = i;
/*10*/ Interlocked.Increment(ref i);
/*11*/ new Thread(() = > DoWork(g)).Start();
/*12*/
/*13*/ }
/*14*/
/*15*/ Console.ReadLine();
/*16*/ } …Run Code Online (Sandbox Code Playgroud) WaitHandle.WaitAll()使用Visual Studio的内置单元测试解决方案时,有没有办法进行单元测试.当我尝试在Visual Studio中运行使用此函数的测试时,测试失败,并在检查测试结果时显示以下错误:
WaitAll for multiple handles on a STA thread is not supported
Run Code Online (Sandbox Code Playgroud)
我希望能够对单元测试的使用进行单元测试,WaitAll()因为越来越多的API代码库现在转移到一种IAsyncResult模式,而不是其他方式进行多线程操作.
编辑
根据Anthony的建议,这里有一个简单的辅助方法,可用于在单元测试环境中调用此类代码:
public static void TestInMTAThread(ThreadStart info)
{
Thread t = new Thread(info);
t.SetApartmentState(ApartmentState.MTA);
t.Start();
t.Join();
}
Run Code Online (Sandbox Code Playgroud) 根据MSDN文档,ManualResetEvent(或任何EventWaitHandle)上的Set()和Reset()返回一个布尔指示符,无论操作是否成功.
在什么情况下这个调用可以返回false,如果有的话我应该怎么做?
waithandle ×10
c# ×9
.net ×3
dispose ×1
locking ×1
mstest ×1
mutex ×1
sleep ×1
timeout ×1
unit-testing ×1
waitone ×1
web-services ×1