Безопасно ли использовать логический флаг, чтобы остановить запуск потока в C # - PullRequest
35 голосов
/ 19 марта 2010

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

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();
    }
}

Ответы [ 4 ]

48 голосов
/ 19 марта 2010

Вам лучше пометить это volatile хотя:

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

Но я бы изменил твой цикл:

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

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

5 голосов
/ 19 марта 2010

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

2 голосов
/ 19 марта 2010

Булевы атомарные в C #: http://msdn.microsoft.com/en-us/library/aa691278(VS.71).aspx

0 голосов
/ 19 марта 2010

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

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

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

Это умышленно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...