【问题标题】:Delegates dispatched by dispatcher are never fired调度员派出的代表永远不会被解雇
【发布时间】:2012-02-08 10:04:59
【问题描述】:

我正在尝试触发一个方法作为对 NetworkStream 的异步读取操作的结果。读取操作通过 BeginRead 和 EndRead 完成,导致在 BeginRead 指定的回调中调用 EndRead。所有非常基本的东西。现在,由于回调是在系统生成的线程中完成的,从 NetworkStream 读取的数据不再属于我的线程,即 BeginRead。为了克服这个问题,我编写了一个方法来进一步处理读取的数据,我尝试通过我的 Thread 的调度程序调用它。

// These are created in my Thread
private delegate void ReceiverCallback(IPEndPoint sender, byte[] data);
private Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

回调看起来像这样:

private void DataReceived(IAsyncResult result)
{
    DataReceivedStruct drs = (DataReceivedStruct)result.AsyncState;
    NetworkStream used = drs.stream;
    AutoResetEvent handle = drs.waitHandle;
    used.EndRead(result);
    DispatchRaiseReceived(readBuffer);
    handle.Set();
}

DataReceivedStruct 是一个包含 NetworkStream 和 AutoResetEvent 的简单结构。 ReadBuffer 是一个长度为 1024 的全局私有 byte[],因为 BeginRead 和 EndRead 不是在同一个方法中调用的。

DispatchRaiseReceive 方法如下所示:

private void DispatchRaiseReceived(byte[] data)
{
    dispatcher.BeginInvoke((ReceiverCallback)RaiseReceived, socket.Client.RemoteEndPoint, data);
}

其中 socket 是一个 TcpClient 对象。

分派的方法类似于以下代码。这样做只是通过事件传递数据以进行进一步处理。

private void RaiseReceived(IPEndPoint sender, byte[] data)
{
    if(IsEnabled){
        if (Received != null)
        {
            Received(this, new TCPDataArgs(sender, data));
        }
    }
}

调度程序需要调用的实际方法永远不会被调用。现在从我在网上可以找到的是,它可能与未在正确的线程上创建调度程序有关,因此它永远不会在正确的线程上调用方法。但是,调度程序是在我的线程上创建的,因此不应该适用。

【问题讨论】:

  • 尝试使用 Invoke 而不是 BeginInvoke。报告发生了什么。
  • 同样的效果,它不会被调用。
  • 您确定您的原始线程,即实例化您的类和private Dispatcher dispatcher = Dispatcher.CurrentDispatcher; 的线程此时仍然处于活动状态?
  • 可能由于某种原因调度程序正在关闭。检查HasShutdownStartedHasShutdownFinished 标志。
  • @Avner,是的,因为那是我的 UI-Tread。而且由于程序还在运行,所以我知道 Thread 仍然存在。

标签: c# wpf delegates dispatcher


【解决方案1】:

为了解决这个问题,我明确地从我的 UI 线程中获取了 Dispatcher,并将其传递到我想要使用它的所需位置。这不是尝试使用Dispatcher.CurrentDispatcher 来获取它。你知道吗,它奏效了。现在可以正确调用委托。

显然Dispatcher.CurrentDispatcher 没有得到正确的Dispatcher 我想使用它。

【讨论】:

  • Dispatcher.CurrentDispatcher 从当前线程获取调度程序。每个进程没有一个调度程序。
  • 我知道,但是因为调用 Dispatcher.CurrentDispatcher 的对象是在主 UI-Thread 上创建的,所以我认为可以使用它。我想我错了。
猜你喜欢
  • 2013-08-21
  • 2016-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多