C# 如何确保线程正在等待事件?
我想知道如何确保线程正在等待事件。 假设我有一个引发事件的组件:C# 如何确保线程正在等待事件?,c#,.net,multithreading,C#,.net,Multithreading,我想知道如何确保线程正在等待事件。 假设我有一个引发事件的组件: public delegate void TestHandler(object sender, EventArgs eventArgs); class Producer { public event TestHandler Handler; public void InvokeHandler(EventArgs eventargs) { var handler = Handler;
public delegate void TestHandler(object sender, EventArgs eventArgs);
class Producer
{
public event TestHandler Handler;
public void InvokeHandler(EventArgs eventargs)
{
var handler = Handler;
if (handler != null) handler(this, eventargs);
}
public Producer()
{
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep( (new Random()).Next(0,100) );
InvokeHandler(new EventArgs());
} }); } }
还有一位听众:
class Listener
{
private readonly BlockingCollection<EventArgs> _blockingCollection;
public Listener()
{
var producer = new Producer();
_blockingCollection = new BlockingCollection<EventArgs>(10);
producer.Handler += producer_Handler;
}
void producer_Handler(object sender, EventArgs eventArgs)
{
_blockingCollection.TryAdd(eventArgs); //no error handling for simplicity sake
}
internal void ProcessEvents()
{
while (true)
{
EventArgs eventArgs;
try
{
if (_blockingCollection.TryTake(out eventArgs))
Console.WriteLine("Received event");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} } } }
我获得了预期的行为(有时我通过阻止收集来获得事件)
但是,如果我将此调用打包到任务中:
Task.Factory.StartNew(() => {
var listner = new Listener();
listner.ProcessEvents(); });
我永远不会进入加工部分。
知道为什么吗?我错过了什么明显的东西吗
另一方面,是否有人知道一个模式的良好描述,这将在这里有所帮助?
我希望在一个线程(最好不是主应用程序线程)上拾取事件,然后在单独的线程上处理它们,如果事件数量太多(我假设是典型的阈值),则同时阻塞
提前感谢,为了弄清楚发生了什么,您应该放置一些日志消息,并验证启动新任务时没有引发异常:
Thread listenerThread = new Thread(() =>
{
// print a message when the task is started
Console.WriteLine("Task started!");
var listner = new Listener();
listner.ProcessEvents();
});
// set your thread to background so it doesn't live on
// even after you're
listenerThread.IsBackground = true;
listenerThread.Start();
Thread.Join()与Task.Wait()执行相同的操作。您可以在不指定超时的情况下调用它,也可以指定无限超时,或者如果希望测试停止等待线程完成,则可以指定以毫秒为单位的超时:
// this will block until the thread is complete
listenerThread.Join(Timeout.Infinite);
如果您需要停止测试,则必须执行异步中断。中断在您应该捕获的线程
内引发ThreadInterruptedException
(如ProcessEvents
方法所示):
此外,您使用的是阻止集合,但您没有使用集合的阻止功能。没有理由在集合中没有任何内容时继续重试,相反,您宁愿阻止,直到集合中有内容为止(这就是此集合的设计目的):
愚蠢的我
当我包装我的调用任务时,它在后台线程上运行。
我本该等任务完成后再退出
完成后,即分配:
var task = Task.Factory.StartNew(/*task body*/);
task.Wait();
等待我得到了我想要的。当你说你作为任务启动时从未到达处理部分,发生了什么?程序只是退出了吗?#paul,@stic,正是我想问的。请发送错误消息和堆栈转储。我们可以查看此测试设置的工件。paul,Henk-将重复练习几次,但它只是看起来像是一个干净的运行,刚刚结束忽略到了一段时间(真的)感谢Lirik,我不知道用if包装的TryTake不会被阻塞。只是学习如何将基于监视器的有界缓冲区留在后面…@stic period,是否将其包装在if子句或任何其他子句中都无关紧要。只有…这样做,但我仍然建议您使用阻塞
Take
,而不是n在阻塞TryTake
…此外,当您有一个消费者正在阻塞/等待某个东西时,您可能真的希望在线程中运行它,而不是在任务中运行它(使您能够中断阻塞调用)。我在启动新任务时传递CancellationToken。我使用try/catch包装while外观,并处理取消时引发的异常。我正在尝试远离使用Thread类,将看看我能走多远:-)
listenerThread.Interrupt();
internal void ProcessEvents()
{
while (true)
{
try
{
var myEvent = _blockingCollection.Take();
Console.WriteLine("Received event");
}
catch(ThreadInterruptedException)
{
Console.WriteLine("Thread interrupted!");
break;// break out of the loop!
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
// Do you REALLY want to keep going if there is an unexpected exception?
// Consider breaking out of the loop...
}
}
}
var task = Task.Factory.StartNew(/*task body*/);
task.Wait();