web-dev-qa-db-ja.com

非同期ロックは許可されていません

基本的に、tcpサーバーに対して複数の非同期リクエストを作成したいと思います。現在、同期しているだけで、すべてのネットワーク呼び出しでUIをブロックする動作中のクライアントがあります。複数のリクエストがほぼ同時に発生する可能性があるため、これを試みました:

private object readonly readLock = new object(); 
public async Task UpdateDetailsAsync()
{
    //I want every request to wait their turn before requesting (using the connection) 
    //to prevent a read call from catching any data from another request
    lock (readLock)
    {
        Details details = await connection.GetDetailsAsync();
        detailsListBox.Items = details;
    }
}

これはロックの有効な使用法ではないと私は確信していますが、それは私がコールが彼らの順番を待たせることができると考えることができる唯一の方法です。この種の動作を実現するために使用できるオブジェクトはありますか? Monitorも同じだと思ったので、試しませんでした(マルチスレッドに関するものであることは理解していますが、私が知っているのはそれだけです...)

18
Philippe Paré

あなたが持っている問題のように見えますが、ロックを取得している間スレッドがブロックするので、メソッドは完全に非同期ではありません。これを解決するには、 SemaphoreSlim.WaitAsync を使用できます

private readonly SemaphoreSlim readLock = new SemaphoreSlim(1, 1); 
public async Task UpdateDetailsAsync()
{
    //I want every request to wait their turn before requesting (using the connection) 
    //to prevent a read call from catching any data from another request
    await readLock.WaitAsync();
    try
    {
        Details details = await connection.GetDetailsAsync();
        detailsListBox.Items = details;
    }
    finally
    {
        readLock.Release();
    }
}
45
Jared Moore

この問題は、2015年8月の時点で50,000回を超えるダウンロードが行われたNuGetパッケージNito.AsyncExによって適切に解決されています。

ReadMeから:

AsyncEx async/awaitのヘルパーライブラリ。

.NET 4.5/4.0、iOS、Android、Windows Store 8.0、Windows Phone Silverlight 8.0/7.5、Windows Phone Applications 8.1、Silverlight 5.0/4.0、およびそれらのすべてのポータブルライブラリをサポートします。

[をちょきちょきと切る]

AsyncLock

多くの開発者が、非同期互換の相互排除メカニズムであるAsyncLockにこのライブラリを使用し始めています。 AsyncLockの使用は簡単です。

private readonly AsyncLock _mutex = new AsyncLock();
public async Task UseLockAsync()
{
  // AsyncLock can be locked asynchronously
  using (await _mutex.LockAsync())
  {
    // It's safe to await while the lock is held
    await Task.Delay(TimeSpan.FromSeconds(1));
  }
}

GitHubのC#ソースコード を参照するか、NuGetパッケージNito.AsyncExをインストールしてください。

13
Contango