3

Threadから非静的メソッドにアクセスできるようにするのは1つだけですobject。私は実際にはスレッドを作成しませんが、代わりにタスクを使用します。メソッドを1つの使用法にロックしようとしましたが、機能していません。最初に静的オブジェクトで試しMutex、次に非静的オブジェクトで試しましMutexたが、単純なモニターでも機能しません。

私のコード:

private async void LoadLinkPreview()
    {
        try
        {
            // TODO: FEHLERTRÄCHTIG!
            Monitor.Enter(_loadLinkMonitor);
            Debug.WriteLine(DateTime.Now + ": Entered LinkPreview");

            // Code ...
            // There are also "await" usages here, don't know if this matters
        }
        catch { }
        finally
        {
             Monitor.Exit(_loadLinkMonitor);
             Debug.WriteLine(DateTime.Now + ": Left LinkPreview");
        }
    }

これがコンソールに表示されるものです。

3/12/2013 6:10:03 PM: Entered LinkPreview
3/12/2013 6:10:05 PM: Entered LinkPreview
3/12/2013 6:10:05 PM: Left LinkPreview
3/12/2013 6:10:06 PM: Left LinkPreview

もちろん、希望どおりに動作することもありますが、常に動作させたいと思います。誰かが私を助けることができますか?

編集:「左」WriteLine()はモニターを終了した後なので、コンソールディスプレイが望ましい動作である可能性があることに気付きましたが、今すぐ切り替えて、2つのスレッドが同時に動作していることを確認できます!また、より明白なコンソール結果:

3/12/2013 6:26:15 PM: Entered LinkPreview
3/12/2013 6:26:15 PM: Entered LinkPreview
2 had an error! // Every time the method is used I count up now, this confirms that the second
// time the method is called the error is produced, which would not happen if the monitor
// is working because I have an if statement right upfront ...
3/12/2013 6:26:17 PM: Left LinkPreview
3/12/2013 6:26:18 PM: Left LinkPreview
4

3 に答える 3

4

実際には、コード意図したとおりに機能している可能性があり、問題はディスプレイだけにあります。

問題はここにあります:

 Monitor.Exit(_loadLinkMonitor);
 Debug.WriteLine(DateTime.Now + ": Left LinkPreview");

モニターを終了した、タイムスタンプを書き出します。モニターに入るのを待っている他のコードExitは、呼び出されるとすぐに実行を開始できることに注意してください。したがって、現在のスレッドがexitを呼び出すことが可能であり、Debug呼び出しの前に、他のスレッドがEnter監視して「Entered」行に書き込むことができます。

コードを次のように変更した場合:

 Debug.WriteLine(DateTime.Now + ": Left LinkPreview");
 Monitor.Exit(_loadLinkMonitor);

そうすれば、動作は変わりませんが、ロギングのバグは削除されます。それでも故障している場合は、コードのどこかに問題があります。

ちなみに、メソッドがあるasync場合は、などのブロッキング待機を行うメソッドを呼び出さないようにする必要がありますMonitor.Enter。を使用する場合SemaphoreSlimWaitAsync、そのメソッドを使用して、メソッドがブロックされないようにすることができます。これは次のようになります。

private SemaphoreSlim semaphore = new SemaphoreSlim(1);
private async void LoadLinkPreview()
{
    try
    {
        await semaphore.WaitAsync();
        Debug.WriteLine(DateTime.Now + ": Entered LinkPreview");
        await Task.Delay(2000);//placeholder for real work/IO
    }
    finally
    {
        Debug.WriteLine(DateTime.Now + ": Left LinkPreview");
        semaphore.Release();
    }
}
于 2013-03-12T17:27:48.130 に答える
4

編集:そのすべてを捨てた。答えは次のとおりです。lockステートメントの本文内で「await」演算子を使用できないのはなぜですか?

基本的に「lock」ステートメント内で「await」を使用して、実行しようとしていることを実行することは想定されていません。

于 2013-03-12T17:37:01.380 に答える
0

メソッドなどの標準のマルチスレッドプリミティブは使用できませんMonitorasyncステートメントを使用すると、C#コンパイラは停止しますlockが、それを「手動で」Monitor.Enter実行すると、足を踏み入れてしまうことになります。

少し考えてみると、それは完全に理にかなっています。asyncメソッドが降伏するとどうなりますか?未完了を返し、(a)待機中に他のコードを実行できるようにしますこれは、ロックが保持されている間、他のコードが実行されないようにするというロックのポイントに完全に反します。メソッドが別のスレッドで再開する状況(ASP.NETやスレッドプールコンテキストなど)もあります。この場合、1つのスレッドがロックを取得し、別のスレッドがそれを解放します。狂気!猫と犬が一緒に暮らす!Taskasync

組み込みの.NETソリューションはです。これはロック/セマフォとして機能します(ただし、で使用するためのSemaphoreSlim組み込みはありません)。Stephen Toubは、調整プリミティブに関するブログシリーズを作成しました。AsyncExライブラリに完全なスイートが実装されており、 NuGetから入手できます。IDisposableusingasync

于 2013-03-12T18:13:26.617 に答える