0

私は次のような方法を持っています:

void Foo ()
{
    bool flag;
    do
    {
        flag = false;

        var check = CheckSomething();
        if(check)
        {
            DoSomething();
            flag = true;
        }
    }
    while(flag);
}

現在、次のコード スニペットを使用してメソッドを呼び出しています (多くのワーカー スレッドで実行されます)。

Bar(); // this method may affect the outcome of CheckSomething()
ThreadPool.QueueUserWorkItem(state => Foo());
  • Bar() が呼び出された直後にループ本体が常に実行されることが重要ですが
  • CheckSomething()Foo()費用がかかるので、必要以上に電話をかけたくない

Foo()まだ実行されておらず、終了する前に呼び出す場合にのみ、安全に呼び出す方法はありCheckSomething()ますか?

4

2 に答える 2

3

私があなたを正しく理解Fooしていれば、すでに実行されている場合は実行を防ぎたいと考えています。そのためにモニターを使用できるようです。

private object fooLock = new object();

void Foo ()
{
    // Try to acquire the lock
    if (!Monitor.TryEnter(fooLock))
    {
        // Some other thread is already in this method.
        return;
    }

    bool flag;
    do
    {
        flag = false;

        var check = CheckSomething();
        if(check)
        {
            DoSomething();
            flag = true;
        }
    }
    while(flag);

    // release the lock
    Monitor.Exit(fooLock);
}

(なぜ節に を入れなかったのか疑問に思っている人は、Eric Lippert の Locks and exceptions do not mix を参照Monitor.Exitしてください。)finally

呼び出されるのを防ぐことはできませんがFoo、複数のスレッドがループに入るのを防ぐため、CheckSomething内から同時に呼び出すことはできませんFoo

あなたの要件は少しあいまいなので、これがあなたが望むことを正確に行わない可能性があります. 1 つのスレッドが既に呼び出されCheckSomethingfalse戻ってきたが、まだ終了しておらず、別のスレッドがメソッドに入った場合に、何をしたいかについてはあいまいな点があります。その競合状態の処理は少しトリッキーになります。

于 2013-09-09T20:42:25.480 に答える
1

Servy のコメントの助けを借りて、共有メモリをバージョン管理することで問題を解決できました。

  • を呼び出すたびBarに、基礎となる共有メモリのバージョンが増加します
  • Bar私が引き継いだ新しい現在のバージョンを返しますFoo
  • Foo現在のバージョンをCheckSomething-wrapperに渡します
  • CheckSomething-wrapper は、指定されたバージョンが共有メモリの現在のバージョンよりも小さい場合、すぐに false を返します ->Foo終了します

Bar唯一の問題は、短期間にあまりにも多くの呼び出しがFooメソッドを枯渇させていることです。そのため、バージョンの違いが定数値 (たとえば 50) を超えている場合はとにかく実行します。

ご協力いただきありがとうございます。

于 2013-09-09T21:18:43.853 に答える