2

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

これは、モニターが重要な領域をロックしていないことを意味します。誰かが私が間違っていることの手がかりを持っていますか?

4

2 に答える 2

6

あなたは効果的に使用しようとしています:

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

...ただし、C#コンパイラでは、壊れてしまうため、これを実行できません。式が完了するまでawaitに、別のスレッドにいる可能性があります。したがって、を呼び出すとMonitor.Exit、ロックインを取得したときと同じスレッドにいない可能性があります...したがって例外です。

以下を表示するようにログを変更することをお勧めします。

  • を呼び出すとIn、現在のスレッドとその後の値(別のスレッドがモニターを所有しているため、taken一部のタスクがモニターを正常に取得できなかったことがわかりますが、以下を参照してください)
  • 電話をかける前にMonitor.Exit、どのスレッドを使用しているか

何を達成しようとしているのかは明確ではありませんが、Monitorここで使用するのはほぼ間違いなく間違ったアプローチです。

また、複数のタスクがすべて同じスレッドで実行される可能性があるため(同時にではありませんが、待機してスレッドを「放棄」しているため)、モニターが再入可能であるため(1つのスレッドがモニターを複数回取得できる)、モニターを取得する複数のタスクをよく見てください。

これが機能しない理由を理解すること、およびスレッドがタスクと同じではないことを理解することが重要です。次に、実際に必要なことを達成する方法を検討し始めることができますが、これはほぼ確実に経由ではありませんMonitor

于 2013-03-26T09:41:10.247 に答える
1

Monitorasyncメソッドでは機能しません。

async互換性のある相互排除が必要な場合は、SemaphoreSlim.WaitAsyncまたはAsyncExライブラリの調整プリミティブの1つを試してください。

于 2013-03-26T11:56:39.100 に答える