C# Dispatcher.Invoke';挂起';在Windows服务中异步读取期间

C# Dispatcher.Invoke';挂起';在Windows服务中异步读取期间,c#,multithreading,asynchronous,dispatcher,C#,Multithreading,Asynchronous,Dispatcher,我已经基于ServiceBase类创建了一个Windows服务。在这个服务中,我创建了NamedPipeClientStream(m_Stream)的一个实例。连接此流后,我使用BeginRead()方法启动异步读取: 在回调例程ReadAsyncCallback中(实际上会被调用),我为流调用EndRead()(在本例中,它给出了读取的字节数2)。接下来,我想向原始线程发出信号,表示读取已经完成。为此,我使用Dispatcher.Invoke方法: m_Dispatcher.Invoke( n

我已经基于ServiceBase类创建了一个Windows服务。在这个服务中,我创建了NamedPipeClientStream(m_Stream)的一个实例。连接此流后,我使用BeginRead()方法启动异步读取:

在回调例程ReadAsyncCallback中(实际上会被调用),我为流调用EndRead()(在本例中,它给出了读取的字节数2)。接下来,我想向原始线程发出信号,表示读取已经完成。为此,我使用Dispatcher.Invoke方法:

m_Dispatcher.Invoke( new ReadDelegate( this.OnRead ), bytesRead);
(m_Dispatcher是使用System.Windows.Threading.Dispatcher.CurrentDispatcher在原始线程中创建的。)

此时,我期望OnRead方法在原始线程中被调用,但它没有。Invoke()方法没有返回,它似乎是挂起的

我希望有人能帮我。请让我知道如果你需要更多的信息,我会尽快给你

您好,
Richard

系统.Windows.Threading.Dispatcher需要正确配置的
同步上下文才能正常工作。当在WPF应用程序的上下文中时,会自动为您创建同步上下文,但是在Windows服务中不会发生这种情况,这就是为什么您会看到挂起的原因

另外,除了同步上下文之外,因为我相信
调度程序
的工作方式与Windows窗体中的
控件类似。Invoke
BackgroundWorker
,Windows服务主线程必须泵送一个消息循环,以便您能够将调用注入其中

我写了一篇博客,介绍了
BackgroundWorker
类如何根据其运行的上下文(Windows窗体、控制台或Windows服务)做出不同的反应,您可能会发现这是一篇有趣的文章,因为该类使用的机制类似于WPF
Dispatcher

最后,要更深入地了解同步上下文的工作原理,您应该阅读:


调用
CurrentDispatcher
的线程可能出于某种原因没有发送消息。最可能的原因是因为它没有任何消息泵送机制。要使
Invoke
正常工作,目标线程必须专门设计为接受委托注入。这通常是通过让目标线程在无限循环中旋转,等待消息出现在队列中来实现的。然后,另一个线程将提交一条特殊消息,请求执行委托。这些都是在Windows窗体或WPF应用程序的UI线程上自动设置的。除非您手动启动,否则它将不存在于Windows服务应用程序中

无论如何,我不会尝试使用这种委托封送技术(或任何将委托同步注入另一个线程的技术)。原因是它将导致在
线程池
线程或IO完成端口线程上执行的异步IO回调阻塞,直到封送的委托完成。您不希望以这种方式绑定IO

相反,您应该将从流中读取的数据发布到共享数据结构(如队列或列表)中,然后让原始线程在特定的时间间隔提取数据。如果期望原始线程等待从流中读取数据,那么可以设置生产者-消费者模式。使用
BlockingCollection
,这非常简单。原始线程将调用
Take
,直到项目到达,IO回调将通过调用
Add
发布数据


还有其他可以接受的处理方法,但调用
Invoke
可能不是其中之一。

感谢Brian和Joao的回答和提示。事实上,我的服务中没有运行消息泵。我决定按照Brian的建议离开“调用”路径,改用共享数据结构。
m_Dispatcher.Invoke( new ReadDelegate( this.OnRead ), bytesRead);