2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

非同期手続きの中でロックを掛ける

Posted at

参考

この記事は、以下の動画を参考にしています。
詳しくは、動画をご覧ください。

リファレンス

非同期手続きの中ではlock文が使えない

asyncを使った非同期手続きの中で、awaitを付けた非同期呼び出しを含む文ブロックを、lock文を使ってロックを掛けようとすると、ビルドエラーになる。

private static readonly Lock _lock = new();

public async Task DoWorkAsync()
{
    lock (_lock)
    {
        // 
        await DoSubWorkAsync(); // ビルドエラー
        //
    }
}

lock文を使わず、System.Threading.Lockクラスのメソッドを使い、ロックの取得と解放をすると、ビルドエラーにはならない。

しかし、Lockクラスのロックはスレッドに掛けられるため、awaitの前後が異なるスレッドで実行される可能性のある非同期手続きでは、正常にロックが動作しない。(参照

private static readonly Lock _lock = new();

public async Task DoWorkAsync()
{
    _lock.Enter(); // ここを実行するスレッドと…
    
    try
    {
        // 
        await DoSubWorkAsync(); // ビルドエラーにはならない
        //
    }
    finally
    {
        _lock.Exit(); // ここを実行するスレッドが、異なる可能性がある
    }
}

セマフォを使ってロックを掛ける

そこで非同期手続きでは、System.Threading.SemaphoreSlimクラスのオブジェクトを用いて、ロックを掛けるとよい。

private static readonly SemaphoreSlim _semaphore = new(initialCount: 1, maxCount: 1);

public async Task DoWorkAsync()
{
    await _semaphore.WaitAsync(); // ロックを掛ける
    
    try
    {
        // 
        await DoSubWorkAsync();
        //
    }
    finally
    {
        _semaphore.Release(); // ロックを解放する
    }
}

ロックを掛ける際、タイムアウトを指定することもできる。

var locked = await _semaphore.WaitAsync(timeout: TimeSpan.FromSeconds(1));
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?