相关疑难解决方法(0)

由非托管应用程序托管的托管组件中的Await和SynchronizationContext

[EDITED] 这似乎是 Framework的Application.DoEvents实现中的一个错误,我在这里报告.在UI线程上恢复错误的同步上下文可能会严重影响像我这样的组件开发人员.赏金的目标是更多地关注这个问题,并奖励@MattSmith,他的答案帮助追踪它.

我负责通过COM互操作UserControl将基于.NET WinForms 的组件作为ActiveX暴露给传统的非托管应用程序.运行时要求是.NET 4.0 + Microsoft.Bcl.Async.

该组件被实例化并在应用程序的主要STA UI线程上使用.它的实现使用async/await,因此它期望在当前线程(即,WindowsFormsSynchronizationContext)上安装序列化同步上下文的实例.

通常,WindowsFormsSynchronizationContext设置为Application.Run,托管应用程序的消息循环运行的位置.当然,这不是非托管主机应用程序的情况,我无法控制它.当然,主机应用程序仍然有自己的经典Windows消息循环,因此序列化await延续回调应该不是问题.

但是,到目前为止我提出的解决方案都不是完美的,甚至都不能正常工作.这是一个人为的例子,其中Test方法由主机app调用:

Task testTask;

public void Test()
{
    this.testTask = TestAsync();
}

async Task TestAsync()
{
    Debug.Print("thread before await: {0}", Thread.CurrentThread.ManagedThreadId);

    var ctx1 = SynchronizationContext.Current;
    Debug.Print("ctx1: {0}", ctx1 != null? ctx1.GetType().Name: null);

    if (!(ctx1 is WindowsFormsSynchronizationContext))
        SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

    var ctx2 = SynchronizationContext.Current;
    Debug.Print("ctx2: …
Run Code Online (Sandbox Code Playgroud)

.net c# asynchronous com-interop async-await

17
推荐指数
2
解决办法
2291
查看次数

缺少非捕获Task.Yield迫使我使用Task.Run,​​为什么要这样做呢?

如果这个问题是基于意见的,请提前道歉.这里已经讨论了缺少不捕获执行上下文的Task.Yield版本.显然,这个功能在早期版本的Async CTP中以某种形式出现,但由于它很容易被滥用而被删除.

IMO,这样的功能可能很容易被滥用Task.Run.这就是我的意思.想象一下,有一个等待的SwitchContext.YieldAPI可以调度ThreadPool上的延续,因此执行将始终在与调用线程不同的线程上继续.我可以在下面的代码中使用它,它从UI线程启动一些CPU绑定的工作.我认为这是一种在池线程上继续CPU绑定工作的便捷方式:

class Worker
{
    static void Log(string format, params object[] args)
    {
        Debug.WriteLine("{0}: {1}", Thread.CurrentThread.ManagedThreadId, String.Format(format, args));
    }

    public async Task UIAction()
    {
        // UI Thread
        Log("UIAction");

        // start the CPU-bound work
        var cts = new CancellationTokenSource(5000);
        var workTask = DoWorkAsync(cts.Token); 

        // possibly await for some IO-bound work 
        await Task.Delay(1000);
        Log("after Task.Delay");

        // finally, get the result of the CPU-bound work
        int c = await workTask;
        Log("Result: {0}", …
Run Code Online (Sandbox Code Playgroud)

.net c# multithreading task-parallel-library async-await

3
推荐指数
1
解决办法
978
查看次数