.NET 创建新的调度程序员。

14
我正在尝试使用dispatcher创建第二个线程,这样我就可以完全无压力地使用主要的dispatcher(用于UI),并且让UI始终响应。现在,我可以为每个子程序(或C#中的void)创建多个线程,但是难道我不能创建一个新的线程并获取它的dispatcher,并对其进行调用吗?这是我所做的:
Private CheckLoopThread As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf CheckLoop))

CheckLoopThread.Priority = System.Threading.ThreadPriority.Lowest
CheckLoopThread.Start()
Dim Test As Windows.Threading.Dispatcher = Windows.Threading.Dispatcher.FromThread(CheckLoopThread)

然而,变量“Test”在执行后变成了“Nothing”。这怎么可能?是否有另一种方法创建第二个调度程序?

任何.NET形式的答案都会被赞赏。Visual Basic或C#。我正在使用VB.NET WPF在.NET 4.0框架上进行工作。

提前致谢。


确保CheckLoopThread在启动后不会立即结束(如果线程运行的是一个执行时间不长的CheckLoop过程)。 - Mathias Lykkegaard Lorenzen
检查循环内部嵌套了一个不会结束的循环。 - René Sackers
3个回答

18

为什么需要锁定?

我更喜欢:

Dispatcher myDispatcher = null;

// create a manual reset event for crossthread signalling.
var dispatcherReadyEvent = new ManualResetEvent(false);

// create a new thread.
new Thread(new ThreadStart(() =>
{
    // get the current dispatcher (if it didn't exists
    // it will be created.
    myDispatcher = Dispatcher.CurrentDispatcher;
    // set the signal that the dispatcher is created.
    dispatcherReadyEvent.Set();
    // run the dispatcher.
    Dispatcher.Run();
})).Start();

// wait until the dispatcher is created on the thread.
dispatcherReadyEvent.WaitOne();

// run something on the dispatcher thread.
myDispatcher.Invoke(...);

1
非常正确,虽然我不确定底层实现是否相同。 - mycroes
这是一个老问题,但实际上并非如此。Lock 在监视器的 TryEnter 调用周围使用了一个 try 块。 - AsPas

13
若线程尚未创建 Dispatcher,则调用 Dispatcher.FromThread(...) 方法将返回 null。要为线程创建 Dispatcher,需要在 CheckLoopThread 上至少访问一次 Dispatcher.CurrentDispatcher。正如 MSDN 中针对 Dispatcher.CurrentDispatcher 所述:如果当前线程没有关联的 Dispatcher,则会创建一个新的 Dispatcher。但是 FromThread 方法不会这样做,如果指定的线程没有关联的 Dispatcher,则返回 null。请注意保留原始的 HTML 标记。

非常感谢!确实就是这样。+1 给你。 - René Sackers
对于那些使用 RedGate 的 .NET Reflector(至少在 2021 年,版本为 10.3.1.1956),有一个重要的提示和警告:该产品对于简单的两行函数 Dispatcher.get_CurrentDisptacher 显示了明显错误的 C# 代码。该代码错误地声称每次访问 Dispatcher.CurrentDispatcher 属性时都会创建一个新的 Dispatcher()。但是通过切换到该产品的 IL 显示,您可以看到这并不是真实情况。 - Glenn Slayden
在这个领域还有一个警告(与我刚提到的错误无关),那就是微软在这里的设计非常令人困惑。即:Dispatcher.CurrentDispatcher 是一个(静态)“具有副作用的属性”(噫!),而(静态)方法 Dispatcher.FromThread(...) - 基本上做同样的事情 - 实际上是不带副作用的。如果交换这两个的语义,设计将更清晰,并且会产生更少的错误预期。 - Glenn Slayden

5

我实际上正在创建很多这些调度程序,我想正确的方式是按照以下方式:

object theLock = new object();
Dispatcher dispatcher = null;

lock (theLock)
{
    new Thread(new ThreadStart(() =>
    {
        lock (theLock)
        {
            dispatcher = Dispatcher.CurrentDispatcher;
            Monitor.Pulse(theLock);
        }
        Dispatcher.Run();
    })).Start();

    Monitor.Wait(theLock);
}

dispatcher.Invoke(...);

看起来所有的锁定都很复杂,但理论上 Start() 方法可以在实际设置 dispatcher 之前返回,因此在没有锁定的情况下调用它可能会导致 NullReferenceException


这对我有用。谢谢! - aclave1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接