2

言語固有ではありませんが、C# には次のようなものがあります。

public static void StartJob() {
    ThreadPool.QueueUserWorkItem(s => {
        if (Monitor.TryEnter(_lock)) {
            ProcessRows();
            Monitor.Exit(_lock);
        }
    }
);

ProcessRows()すべての行が削除されるまで、データベース内の行を処理して削除します。プログラムの起動時、およびプログラムの他の場所で行がデータベースに追加されるたびに、StartJobが呼び出され、プログラムをブロックすることなくすべての行が処理されるようにします。現在、ロックを解放しようとしているのとまったく同時に行が追加された場合、その行はStartJob処理されません。

すべての行が確実に処理されるようにするにはどうすればよいですか? ProcessRows()行が追加されない限り、実行しないことを好みます。

4

1 に答える 1

2

メソッドをロックしないでください。実行中かどうかを示すフラグを使用して、メソッド内でロックします。

1 つの実装は次のコードのようになります。この場合、すべてのロジックを に移動しProcessRows、メソッドが既に実行されている場合はすぐに戻るようにしました。

public static bool _isRunning = false;

public static void StartJob() 
{ 
    ThreadPool.QueueUserWorkItem(s => { ProcessRows(); })
} 

public static void ProcessRows()
{
    Monitor.Enter(_lock);
    if (_isRunning) 
    {
        Monitor.Exit(_lock);
        return;
    }

    _isRunning = true;

    while (rowsToProcess)
    {
        Monitor.Exit(_lock);;

        // ... do your stuff

        Monitor.Enter(_lock);
    }

    _isRunning = false;
    Monitor.Exit(_lock);
}

この構造では、while設定せずにループを完了することは不可能です。_isRunning = falseそうでない場合、メソッドの別のインスタンスが開始されたときにループが完了すると、競合状態が発生します。同様に、メソッドが呼び出されると、常にループに入り、_isRunning = true別のインスタンスが実行される前に設定されます。

于 2012-09-19T14:35:14.340 に答える