如何确保线程正在等待事件?

时间:2011-02-22 22:33:52

标签: 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;
        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(); });

我永远不会进入处理部分。 知道为什么会这样吗?我会错过一些明显的东西吗?

另一方面,是否有人知道对这种模式的良好描述? 我想在一个线程上拾取事件(最好不是主应用程序线程),然后在一个单独的线程上处理它们同时阻塞事件的数量是否过高(典型的阈值假设)

提前致谢,

2 个答案:

答案 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...
        } 
    } 
}