[解決済み] ロックステートメントのボディ内で 'await' 演算子を使用できないのはなぜですか?
質問
C# (.NET Async CTP)のawaitキーワードは、lock文の中からは使用できない。
から MSDN :
を使用します。 await 式は使用できません。 同期関数、クエリ 例外処理のキャッチブロックやファイナルブロックの中にある ステートメントを使用します。 ロックステートメントのブロック内 または安全でないコンテキストで
これは、コンパイラーチームが何らかの理由で実装するのが難しいか不可能なのだと思います。
using文で回避策を試みました。
class Async
{
public static async Task<IDisposable> Lock(object obj)
{
while (!Monitor.TryEnter(obj))
await TaskEx.Yield();
return new ExitDisposable(obj);
}
private class ExitDisposable : IDisposable
{
private readonly object obj;
public ExitDisposable(object obj) { this.obj = obj; }
public void Dispose() { Monitor.Exit(this.obj); }
}
}
// example usage
using (await Async.Lock(padlock))
{
await SomethingAsync();
}
しかし、これは期待通りに動作しません。 ExitDisposable.Dispose 内の Monitor.Exit の呼び出しは、他のスレッドがロックを取得しようとすると、(ほとんどの場合)無期限にブロックされてデッドロックを引き起こすようです。 私は、私の回避策の信頼性の低さと、await文がlock文の中で許可されていない理由が、何らかの形で関連していると考えています。
どなたかご存知ですか? なぜ await は lock 文の本文中では使用できないのですか?
解決方法は?
<ブロッククオートこれは、コンパイラチームが何らかの理由で実装するのが難しいか不可能なのだと思います。
いいえ、実装が難しいとか不可能ということは全くありません。あなたが自分で実装したことがその証です。むしろ、そうです。 それは信じられないほど悪い考えです そのため、このような失敗をしないように、許可していないのです。
ExitDisposable.Dispose 内の Monitor.Exit の呼び出しは、他のスレッドがロックを取得しようとするため、(ほとんどの場合)無期限にブロックされてデッドロックが発生するようです。私は、私の回避策の信頼性の低さと、await 文が lock 文で許可されない理由が、何らかの形で関連していると考えています。
正解です!なぜ違法としたのかがわかりましたね。 ロックの内側で待機することは、デッドロックを発生させるレシピです。
その理由はおわかりいただけたかと思います。 await が呼び出し元に制御を返してからメソッドが再開するまでの間に、任意のコードが実行されます。 . その任意のコードは、ロックの順序を逆転させ、デッドロックを発生させるロックを取り出している可能性があります。
さらに悪いことに コードが別のスレッドで再開される可能性がある (高度なシナリオでは、通常は await を実行したスレッドで再び拾いますが、そうとは限りません) その場合、ロックを解除すると、ロックを取り出したスレッドとは別のスレッドでロックを解除することになります。これは良いアイデアでしょうか?いいえ。
を行うことも"ワーストプラクティス"であることに注意してください。
yield return
の中に
lock
というのは、同じ理由です。そうすることは合法ですが、違法にすればよかったのにと思います。私たちは、"await"のために同じ過ちを犯すつもりはありません。
関連
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】Unity3DでOnTriggerEnterが動作しない件
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み] lockステートメントは、ボンネットの中で何をするのでしょうか?
-
[解決済み] 補間文字列の内部で三項演算子を使用するには?
-
[解決済み] トップレベルでasync/awaitを使用するにはどうすればよいですか?
-
[解決済み】オブジェクトを渡すときに'ref'キーワードを使用するのはなぜですか?
-
[解決済み】C# 5 非同期 CTP:生成されたコードで EndAwait 呼び出しの前に内部の "state" が 0 に設定されるのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】コンパイルエラー「未割り当てのローカル変数を使用しています」が発生したのはなぜですか?
-
[解決済み】Excel "外部テーブルが期待された形式ではありません。"
-
[解決済み】統合マネージドパイプラインモードで適用されないASP.NETの設定が検出された
-
[解決済み】C# ASP.NET使用時に「WebClientのリクエスト中に例外が発生しました。
-
[解決済み】Unity 「関連するスクリプトを読み込むことができません」「Win32Exception: システムは指定されたファイルを見つけることができません"
-
[解決済み] 2つのリストを結合する
-
[解決済み】パラメータ付きRedirectToAction
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する
-
[解決済み】WebResource.axdとは何ですか?