14

マルチスレッドアプリケーションにメソッドがあり、このメソッドが呼び出されたときに次の動作が必要です。

  1. 他のスレッドが現在メソッドを実行していない場合は、それを実行します。
  2. 別のスレッドが現在メソッドを実行している場合は、実行せずにメソッドを終了します。

C#のlockステートメントは、スレッドが実行を完了するまで待機するのに役立ちますが、このメソッドへのアクセスをシリアル化するのではなく、別のスレッドによって実行されている場合は、このメソッドの実行をバイパスします。

4

4 に答える 4

13

これは、Monitor.TryEnterを使用して実行できますが、おそらくもっと簡単です。インターロック:

int executing; // make this static if you want this one-caller-only to
               // all objects instead of a single object
void Foo() {
    bool won = false;
    try {
        won = Interlocked.CompareExchange(ref executing, 1, 0) == 0;
        if(won) {
           // your code here
        }
    } finally {
        if(won) Interlocked.Exchange(ref executing, 0);
    }

}
于 2012-09-13T18:14:06.047 に答える
9

私は理解していないと思います...一度に1つのスレッドだけによって呼び出される必要がある場合、なぜ複数のスレッドが最初にそれを呼び出すのですか?

とにかく、 Monitor.TryEnter()を使用できます。ブロックせずfalse、ロックの取得に失敗した場合は戻ります。その場合は、関数から戻ることができます。

于 2012-09-13T18:09:19.473 に答える
0

別の場所にbool変数を作成し、メソッドの開始時にtrueに設定し、メソッドの終了時にfalseに設定します。メソッドを実行する前に、変数がfalseかどうかを確認してから、メソッドから終了します。

于 2012-09-13T18:08:50.207 に答える
0

この目的のためのヘルパーメソッドは次のとおりです。

static class Throttle
{
    public static void RunExclusive(ref int isRunning, Action action)
    {
        if (isRunning > 0) return;

        bool locked = false;
        try
        {
            try { }
            finally
            {
                locked = Interlocked.CompareExchange(ref isRunning, 1, 0) == 0;
            }

            if (locked) action();
        }
        finally 
        { 
            if (locked) 
                Interlocked.Exchange(ref isRunning, 0); 
        }
    }
}

次のように使用します。

private int _isTuning = 0;
private void Tune() { ... }

...

Throttle.RunExclusive(ref _isTuning, Tune);
于 2012-09-13T18:25:14.233 に答える