阻塞和等待一个事件 [英] Blocking and waiting for an event

查看:168
本文介绍了阻塞和等待一个事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时候想阻止我的线程在等待会发生的事件。

我通常做的是这样的:

 私人的AutoResetEvent _autoResetEvent =新的AutoResetEvent(假);

私人无效的OnEvent(对象发件人,EventArgs的){
  _autoResetEvent.Set();
}

// ...
button.Click + =的OnEvent;
尝试{
  _autoResetEvent.WaitOne();
}
最后{
  button.Click  -  =的OnEvent;
}
 

不过,看来这应该是我能提取到一个公共类(甚至一些已经存在的框架)。

我希望能够做这样的事情:

  EventWaiter EW =新EventWaiter(button.Click);
ew.WaitOne();
EventWaiter EW2 =新EventWaiter(form.Closing);
ew2.WaitOne();
 

但我真的不能找到一个方法来构建这样一个类(我无法找到传递事件作为一个参数一个很好的有效的方法)。任何人都可以帮忙吗?

要给予为什么这可能是有用的一个例子,考虑这样的事情:

  VAR状态= ShowStatusForm();
status.ShowInsertUsbStick();
布尔取消= WaitForUsbStickOrCancel();
如果(!取消){
  status.ShowWritingOnUsbStick();
  WriteOnUsbStick();
  status.AskUserToRemoveUsbStick();
  WaitForUsbStickToBeRemoved();
  status.ShowFinished();
}其他{
  status.ShowCancelled();
}
status.WaitUntilUser pressesDone();
 

这是不是相当于code写入逻辑US $ p $垫了许多方法之间更加简洁易读。但要实现WaitForUsbStickOrCancel(),WaitForUsbStickToBeRemoved和WaitUntilUser pressesDone()(假设我们得到一个事件时,U盘,插入或删除)我需要重写EventWaiter各一次。当然,你必须要小心,从来没有在GUI线程上运行,这一点,但有时这是一个值得权衡的简单code。

另一种选择将是这个样子:

  VAR状态= ShowStatusForm();
status.ShowInsertUsbStick();
usbHandler.Inserted + = OnInserted;
status.Cancel + = OnCancel的;
// ...
无效OnInserted(/*..*/){
  usbHandler.Inserted  -  = OnInserted;
  status.ShowWritingOnUsbStick();
  MethodInvoker MI =()=> WriteOnUsbStick();
  mi.BeginInvoke(WritingDone,NULL);
}
无效WritingDone(/*..*/){
  / * EndInvoke会* /
  status.AskUserToRemoveUsbStick();
  usbHandler.Removed + = OnRemoved;
}
无效OnRemoved(/*..*/){
  usbHandler.Removed  -  = OnRemoved;
  status.ShowFinished();
  status.Done + = OnDone;
}
/* 等等 */
 

我觉得更难阅读。诚然,这是远远总是流会如此线性的,但是当它是的,我喜欢的第一个样式。

这是与使用ShowMessage()和Form.ShowDialog() - 他们也被阻塞,直到一些事件发生(尽管它们将运行一个消息循环,如果他们被称为GUI线程上)

解决方案

不通过的情况下,通过委托相匹配的事件处理程序的签名。这实际上听起来哈克给我,所以要意识到潜在的死锁问题。

It sometimes want to block my thread while waiting for a event to occur.

I usually do it something like this:

private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

private void OnEvent(object sender, EventArgs e){
  _autoResetEvent.Set();
}

// ...
button.Click += OnEvent;
try{
  _autoResetEvent.WaitOne();
}
finally{
  button.Click -= OnEvent;
}

However, it seems that this should be something that I could extract to a common class (or perhaps even something that already exists in the framework).

I would like to be able to do something like this:

EventWaiter ew = new EventWaiter(button.Click);
ew.WaitOne();
EventWaiter ew2 = new EventWaiter(form.Closing);
ew2.WaitOne();

But I can't really find a way to construct such a class (I can't find a good valid way to pass the event as an argument). Can anyone help?

To give an example of why this can be useful, consider something like this:

var status = ShowStatusForm();
status.ShowInsertUsbStick();
bool cancelled = WaitForUsbStickOrCancel();
if(!cancelled){
  status.ShowWritingOnUsbStick();
  WriteOnUsbStick();
  status.AskUserToRemoveUsbStick();
  WaitForUsbStickToBeRemoved();
  status.ShowFinished();
}else{
  status.ShowCancelled();
}
status.WaitUntilUserPressesDone();

This is much more concise and readable than the equivalent code written with the logic spread out between many methods. But to implement WaitForUsbStickOrCancel(), WaitForUsbStickToBeRemoved and WaitUntilUserPressesDone() (assume that the we get an event when usb sticks are inserted or removed) I need to reimplement "EventWaiter" each time. Of course you have to be careful to never run this on the GUI-thread, but sometimes that is a worthwhile tradeoff for the simpler code.

The alternative would look something like this:

var status = ShowStatusForm();
status.ShowInsertUsbStick();
usbHandler.Inserted += OnInserted;
status.Cancel += OnCancel;
//...
void OnInserted(/*..*/){
  usbHandler.Inserted -= OnInserted;
  status.ShowWritingOnUsbStick();
  MethodInvoker mi = () => WriteOnUsbStick();
  mi.BeginInvoke(WritingDone, null);
}
void WritingDone(/*..*/){
  /* EndInvoke */
  status.AskUserToRemoveUsbStick();
  usbHandler.Removed += OnRemoved;
}
void OnRemoved(/*..*/){
  usbHandler.Removed -= OnRemoved;
  status.ShowFinished();
  status.Done += OnDone;
}
/* etc */

I find that much harder to read. Admittedly, it is far from always that the flow will be so linear, but when it is, I like the first style.

It is comparable to using ShowMessage() and Form.ShowDialog() - they also block until some "event" occurs (though they will run a message-loop if they are called on the gui-thread).

解决方案

Don't pass the event, pass a delegate that matches the event handler signature. This actually sounds hacky to me, so be aware of potential dead lock issues.

这篇关于阻塞和等待一个事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆