使用WinRT意外行为监视类

时间:2013-03-26 09:38:54

标签: c# multithreading winrt-async

似乎Monitor在WinRT商店应用程序中无法正常工作。 我有以下代码:

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        var tasks = Enumerable.Range(0, 10).Select((i)=>new Task(DoWork)).ToArray();
        foreach (var task in tasks)
        {
            task.Start();
        }

        Task.WaitAll(tasks);
    }

    static object lockObject = new Object();//typeof(MainPage)

    protected async void DoWork()
    {
        bool taken =false;
        Monitor.Enter(lockObject, ref taken);
        Debug.WriteLine("In");
        await Task.Delay(1000);
        Debug.WriteLine("Out");
        if (taken) Monitor.Exit(lockObject);
    }

在输出窗口中,我看到:

In
In
In
In
In
In
In
Out
Out
Out
Out
Out
Out
Out
In
Out
A first chance exception of type 'System.Threading.SynchronizationLockException' occurred in App4.exe

这意味着Monitor没有锁定关键区域。 有没有人知道我做错了什么?

2 个答案:

答案 0 :(得分:6)

有效试图使用:

lock (lockObject)
{
    await Task.Delay(1000);
}

...除了C#编译器不允许你这样做,因为它会被破坏。当你的await表达式完成时,你可以在另一个线程上 - 所以当你调用Monitor.Exit时,你很可能不会和你获得锁定在同一个线程上...因此异常。

我建议您将日志记录更改为显示:

  • 当您致电In时,您所处的线程以及之后taken的价值(您可能会看到某些任务尚未成功获取监视器,因为另一个线程拥有它 - 但见下文)
  • 在致电Monitor.Exit之前,您正在使用哪个主题

目前尚不清楚您要实现的目标,但在此处使用Monitor几乎当然是错误的方法。

另请注意,因为多个任务都可以在同一个线程上执行(不是同时执行,而是“放弃”线程等待)并且因为监视器是可重入的(一个线程可以多次获取监视器)你可能会看到多个任务获取监视器。

了解为什么这不起作用 - 并且您了解线程与任务不同是非常重要的。然后你可以尝试开始研究如何实际实现你想要的东西,这几乎肯定不是通过Monitor

答案 1 :(得分:1)

Monitor不适用于async方法。

如果您希望async兼容互斥,请尝试SemaphoreSlim.WaitAsyncone of the coordination primitives in my AsyncEx library