1

MSDN の例を読んでいますhttp://msdn.microsoft.com/en-us/library/system.timers.timer.stop.aspx

timer.stop の例では、Interlocked.CompareExchange の使用方法が正しくないのではないかと疑っています。

private static void HandleElapsed(object sender, ElapsedEventArgs e)
{
    numEvents += 1;

    // This example assumes that overlapping events can be 
    // discarded. That is, if an Elapsed event is raised before  
    // the previous event is finished processing, the second 
    // event is ignored.  
    // 
    // CompareExchange is used to take control of syncPoint,  
    // and to determine whether the attempt was successful.  
    // CompareExchange attempts to put 1 into syncPoint, but 
    // only if the current value of syncPoint is zero  
    // (specified by the third parameter). If another thread 
    // has set syncPoint to 1, or if the control thread has 
    // set syncPoint to -1, the current event is skipped.  
    // (Normally it would not be necessary to use a local  
    // variable for the return value. A local variable is  
    // used here to determine the reason the event was  
    // skipped.) 
    // 
    int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
    if (sync == 0)
    {
        // No other event was executing. 
        // The event handler simulates an amount of work 
        // lasting between 50 and 200 milliseconds, so that 
        // some events will overlap. 
        int delay = timerIntervalBase 
            - timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
        Thread.Sleep(delay);
        numExecuted += 1;

        // Release control of syncPoint.
        syncPoint = 0;
    }
    else
    {
        if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
    }
}

私の質問はこのブロックです

int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)
{
   // lots of code here
    syncPoint = 0;
}

それは好きですか?

int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)
{
// lots of code here
   Interlocked.CompareExchange(ref syncPoint, 0, 1)
}

元の代入 syncPoint = 0;はスレッドセーフではないためです。私は正しいですか?

更新

例を更新しました。ComareExchange の戻り値について質問はありません。私の質問は、この if ブロックの最後にある変数同期点の割り当てについてです。インターロックはまったくありません。

4

1 に答える 1

1

これはアトミックであるため、スレッドセーフです

int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)

つまり、syncPoint が 0 の場合は 1 にして、古い値 (つまり 0) を渡して同期 (ローカル変数) に入れます。次に、交換が行われたかどうかを確認します (古い値が 0 だった場合)

私が違うものにするのは、代わりに

syncPoint = 0;

私は使うだろう

Interlocked.Exchange(ref syncPoint, 0);

他のスレッドが「ロック」が解放されていることをすぐに確認できるようにするためです。そうしないと、現在のスレッドが「書き込み」を遅らせsyncPoint = 0、他のスレッドが「ロック」に入ることができなくなります。

しかし

与えられた例では、これは問題ではありません:HandleElapsedイベントに応答して呼び出されます(タイマーはおそらくOSタイマーを使用します)...イベントが処理された後、メモリ バリア (.NET コード内または Windows OS コード内) により、syncPoint更新他のスレッドから見えるようになります。唯一の違いは、おそらく「今すぐ」ではなく「そのポイントの数百行下」で見えるようになることです。

この理論を確認してみましょう:ここから

SynchronizingObject プロパティが null の場合、ThreadPool スレッドで Elapsed イベントが発生します。Elapsed イベントの処理が Interval より長く続く場合、イベントは別の ThreadPool スレッドで再び発生する可能性があります。この場合、イベント ハンドラーは再入可能にする必要があります。

したがって、イベントは新しいThreadPoolスレッドで発生します...イベントが確実にに返された後ThreadPool...わかりました...確かにMemoryBarrierどこかに(少なくともスレッドをに戻すThreadPoolSleep、同じスレッドが複数回使用)

于 2013-08-15T09:25:31.680 に答える