16

非同期メソッド内に重要なセクションがあるマルチスレッド WindowsPhone8 アプリに取り組んでいます。

内部メソッドが既にコールスタックを取得したのと同じロックを取得している可能性があるネストされた非同期呼び出しを使用している C# でセマフォ/ミューテックスを適切に使用する方法を知っている人はいますか? SemaphoreSlim が答えかもしれないと思ったのですが、デッドロックを引き起こしているようです。

public class Foo
{
    SemaphoreSlim _lock = new SemaphoreSlim(1);

    public async Task Bar()
    {
        await _lock.WaitAsync();

        await BarInternal();

        _lock.Release();
     }

    public async Task BarInternal()
    {
        await _lock.WaitAsync();  // deadlock

        // DO work

        _lock.Release();
     }

}
4

4 に答える 4

14

再帰的なロックは本当に悪い考えです (IMO; リンクは私のブログです)。これは特にコードに当てはまりasyncます。async互換性のある再帰ロックを機能させるのは非常に困難です。ここに概念実証がありますが、公正な警告:このコードを本番環境で使用することはお勧めしませ。このコードはAsyncEx に組み込まれ、十分にテストされていません。

代わりにすべきことは、@svick が述べたようにコードを再構築することです。このようなもの:

public async Task Bar()
{
    await _lock.WaitAsync();

    await BarInternal_UnderLock();

    _lock.Release();
}

public async Task BarInternal()
{
    await _lock.WaitAsync();

    await BarInternal_UnderLock();

    _lock.Release();
}

private async Task BarInternal_UnderLock()
{
    // DO work
}
于 2013-11-06T23:30:32.880 に答える
6

このような状況で私がしたことは次のとおりです(それでも、私はタスクの経験がないので、私を打ち負かさないでください;-)
基本的に、実際の実装を非ロックメソッドに移動し、ロックを取得するすべてのメソッドでこれらを使用します.

public class Foo
{
    SemaphoreSlim _lock = new SemaphoreSlim(1);

    public async Task Bar()
    {
        await _lock.WaitAsync();
        await BarNoLock();
        _lock.Release();
     }

    public async Task BarInternal()
    {
        await _lock.WaitAsync(); // no deadlock
        await BarNoLock();
        _lock.Release();
     }

     private async Task BarNoLock()
     {
         // do the work
     }
}
于 2013-11-06T23:28:35.500 に答える