web-dev-qa-db-ja.com

ブールフラグを使用してC#でのスレッドの実行を停止しても安全ですか?

私の主な懸念はブールフラグです...同期せずに使用しても安全ですか?私はそれがアトミックであることをいくつかの場所で読みました(ドキュメントを含む)。

class MyTask
{
    private ManualResetEvent startSignal;
    private CountDownLatch latch;
    private bool running;

    MyTask(CountDownLatch latch)
    {
        running = false;
        this.latch = latch;
        startSignal = new ManualResetEvent(false);
    }

    // A method which runs in a thread
    public void Run()
    {
        startSignal.WaitOne();
        while(running)
        {
            startSignal.WaitOne();
            //... some code
        }
        latch.Signal();
    }

    public void Stop()
    {
        running = false;
        startSignal.Set();
    }

    public void Start()
    {
        running = true;
        startSignal.Set();
    }

    public void Pause()
    {
        startSignal.Reset();
    }

    public void Resume()
    {
        startSignal.Set();
    }
}

これは、この方法でタスクを設計する安全な方法ですか?提案、改善、コメントはありますか?

注:どこから取得するのかわからない場合に備えて、カスタムCountDownLatchクラスを作成しました。

更新:
これも私のCountDownLatchです。

public class CountDownLatch 
{
    private volatile int m_remain;
    private EventWaitHandle m_event;

    public CountDownLatch (int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}
35
Kiril

あなたはそれをマークする方が良い volatile けれども:

Volatileキーワードは、同時に実行されている複数のスレッドによってフィールドが変更される可能性があることを示します。 volatileと宣言されたフィールドは、シングルスレッドによるアクセスを前提とするコンパイラの最適化の対象ではありません。これにより、常に最新の値がフィールドに表示されます。

しかし、私はあなたのループを変更します:

    startSignal.WaitOne();
    while(running)
    {
        //... some code
        startSignal.WaitOne();
    }

あなたの投稿にあるように、スレッドがstoppedのとき(つまり、Stopが呼び出されたとき)、 'some code'が実行される可能性があり、予期しない可能性があります。間違っていても。

48
Remus Rusanu

ブール値はC#ではアトミックですが、あるスレッドで変更して別のスレッドで読み取る場合は、少なくとも揮発性としてマークする必要があります。それ以外の場合、読み取りスレッドは、実際にレジスタに一度だけ読み取る可能性があります。

5
Michael Burr

ブール値はC#ではアトミックです: http://msdn.Microsoft.com/en-us/library/aa691278(VS.71).aspx

2
Kevin Sylvestre

ところで、私はコードのこの部分に気づきました:

// A method which runs in a thread
    public void Run()
    {
        startSignal.WaitOne();
        while(running)
        {
            startSignal.WaitOne();
            //... some code
        }
        latch.Signal();
    }

Whileブロック内のコードを実行するには、「startSignal.Set()」を使用してワーカースレッドのブロックを2回解除する必要があります。

これは意図的ですか?

0
akapet