Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确保线程正在等待事件?_C#_.net_Multithreading - Fatal编程技术网

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();