Действительно ли безопасно использовать булев флаг, чтобы мешать потоку работать в 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 18 June 2010 в 20:10
поделиться

4 ответа

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

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

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

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

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

48
ответ дан 27 November 2019 в 07:12
поделиться

Логические значения в C # являются атомарными: http://msdn.microsoft.com/en-us/library/aa691278 (VS.71). aspx

2
ответ дан 27 November 2019 в 07:12
поделиться

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

5
ответ дан 27 November 2019 в 07:12
поделиться

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

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

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

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

0
ответ дан 27 November 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: