我想知道如何确保线程正在等待事件。 假设我有一个引发事件的组件:
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);
} } } }
如果我将它作为:
启动class Program
{
static void Main(string[] args)
{
var listner = new Listener();
listner.ProcessEvents();
} }
我得到了预期的行为(我不时通过阻止收集来获取事件。
但是如果我将这个调用包装在Task:
中Task.Factory.StartNew(() => {
var listner = new Listener();
listner.ProcessEvents(); });
我永远不会进入处理部分。 知道为什么会这样吗?我会错过一些明显的东西吗?
另一方面,是否有人知道对这种模式的良好描述? 我想在一个线程上拾取事件(最好不是主应用程序线程),然后在一个单独的线程上处理它们同时阻塞事件的数量是否过高(典型的阈值假设)
提前致谢,
答案 0 :(得分:1)
愚蠢的我......
当我在Task中包装我的调用时,它在后台线程上运行。 我应该等到任务结束才能退出。
完成后,即分配:
var task = Task.Factory.StartNew(/*task body*/);
task.Wait();
等等我得到了我想要的东西。
答案 1 :(得分:0)
为了弄清楚发生了什么,你应该放一些日志消息,并确认在你开始新任务时不会抛出任何异常:
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
内引发Thread
(如ProcessEvents
方法所示):
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...
}
}
}