Подтвердить что ты не робот

Безопасно ли использовать логический флаг, чтобы остановить поток из С#

Моя основная проблема связана с логическим флагом... безопасно ли использовать его без какой-либо синхронизации? Я читал в нескольких местах, что он атомный (включая документацию).

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, если вам интересно, откуда я его получаю.

Update:
Вот мой 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();
    }
}
4b9b3361

Ответ 1

Лучше пометить его volatile, хотя:

Ключевое слово volatile указывает, что поле может быть изменено несколькими одновременное выполнение потоков. поля которые объявлены изменчивыми, не являются при условии оптимизации компилятора, что допускать доступ одним потоком. Эта гарантирует, что самое современное значение всегда присутствует в поле.

Но я бы изменил ваш цикл:

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

Как и в вашем сообщении, "некоторый код" может выполняться, когда поток останавливается (т.е. когда вызывается Stop), что является неожиданным и может быть даже неправильным.

Ответ 2

Булевы являются атомарными в С#, однако, если вы хотите изменить его в одном потоке и прочитать его в другом, вам нужно будет пометить его изменчивым, по крайней мере. В противном случае поток чтения может только прочитать его один раз в регистре.

Ответ 4

Кстати, я просто заметил эту часть кода:

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

Вам потребуется разблокировать рабочий поток дважды, используя "startSignal.Set()" для кода внутри исполняемого блока.

Это намеренно?