23

では、C# Windows サービスの複数のスレッドが同時に実行されるのを防ぐ最善の方法は何だと思いますか (サービスはイベントで atimerを使用しています)。OnElapsed

lock()またはmutex? _

の概念を理解できないようですが、私の場合はmutex使用しても問題ないようですlock()

mutexとにかくの使い方を学ぶのに時間を費やすべきですか?

4

6 に答える 6

68

タイマーをワンショットにして、経過イベント ハンドラーで再初期化します。たとえば、 を使用している場合はSystem.Timers.Timer、次のように初期化します。

myTimer.Elapsed = timer1Elapsed;
myTimer.Interval = 1000; // every second
myTimer.AutoReset = false; // makes it fire only once
myTimer.Enabled = true;

そしてあなたの経過イベントハンドラー:

void timerElapsed(object source, ElapsedEventArgs e)
{
    // do whatever needs to be done
    myTimer.Start(); // re-enables the timer
}

これの欠点は、タイマーが 1 秒間隔で起動しないことです。むしろ、最後のティックの処理が終了してから 1 秒後に起動します。

于 2012-05-04T03:00:26.587 に答える
11

タイマーを使用してスレッドを生成しないでください。スレッドを 1 つだけ開始します。スレッドが作業サイクルを終了したら、次のサイクルが開始されるまでの残り時間を計算します。この間隔が 0 または負の場合は、すぐにループバックして新しいサイクルを開始します。正の場合は、ループバックする前にその間隔でスリープします。

これは通常、終了ティックと開始ティックの間の unsigned int 減算の int 結果を取得することによって行われるため、作業によって取得された経過ティックが得られます。これを目的の間隔から差し引くと、新しい残り時間が得られます。

追加のタイマー スレッドは必要なく、2 つのスレッドが同時に実行される可能性もなく、全体的な設計が簡素化され、継続的な作成/開始/終了/破棄、malloc も new() も、スタックの割り当て/割り当て解除も、GC もありません。

タイマー、ミューテックス、セマフォ、ロックなどを使用するその他の設計は、複雑すぎます。余分なスレッドを作成しない方が簡単で簡単な場合、わざわざ余分なスレッドを synchro で停止しようとするのはなぜですか?

場合によっては、sleep() ループの代わりにタイマーを使用するのは、本当に悪い考えです。これは、それらの時間の 1 つのように聞こえます。

public void doWorkEvery(int interval)
{
    while (true)
    {
        uint startTicks;
        int workTicks, remainingTicks;
        startTicks = (uint)Environment.TickCount;
        DoSomeWork();
        workTicks=(int)((uint)Environment.TickCount-startTicks);
        remainingTicks = interval - workTicks;
        if (remainingTicks>0) Thread.Sleep(remainingTicks);
    }
}
于 2012-05-04T01:33:09.363 に答える
3

私はあなたが何をしようとしているのか知っていると思います。コールバックを定期的に実行するタイマー(タイマーの定義)があり、そのコールバックは少しの作業を行います。そのビットの作業は、実際にはタイマー期間よりも時間がかかる可能性があります(たとえば、タイマー期間は500ミリ秒であり、コールバックの特定の呼び出しには500ミリ秒以上かかる可能性があります)。これは、コールバックを再入可能にする必要があることを意味します。

再入可能になれない場合(そして、これが行われる理由はさまざまです)。私が過去に行ったことは、コールバックの開始時にタイマーをオフにし、最後にタイマーをオンに戻すことです。例えば:

private void timer_Elapsed(object source, ElapsedEventArgs e)
{
    timer.Enabled = false;
    //... do work
    timer.Enabled = true;
}

実際に1つの「スレッド」を次々に実行したい場合は、タイマーを使用することはお勧めしません。Taskオブジェクトを使用することをお勧めします。例えば

Task.Factory.StartNew(()=>{
    // do some work
})
.ContinueWith(t=>{
    // do some more work without running at the same time as the previous
});
于 2012-05-04T03:08:40.920 に答える
2

同じプロセス/アプリ ドメイン内の2 つのスレッドが同時に実行されないようにすることだけが必要な場合は、このlockステートメントで十分でしょう。

ただし、クリティカル セクションへのアクセスを待機している間lock、他のスレッドはロックされたままになることに注意してください。それらは中止されたり、リダイレクトされたりしません。それらはそこに座って、元のスレッドがlockブロックの実行を終了して実行できるようになるのを待っています。

A のmutex方がより細かく制御できます。プロセス間でスレッドをロックおよびロックするのではなく、2 番目以降のスレッドを完全に停止させる機能が含まれます。

于 2012-05-04T01:05:08.107 に答える