Безопасно ли использовать логический флаг, чтобы остановить запуск потока в 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();
}
}
4 ответа
Вы лучше отметьте это volatile
хоть:
Ключевое слово volatile указывает, что поле может быть изменено несколькими одновременно выполняющимися потоками. Поля, которые объявлены как volatile, не подлежат оптимизации компилятора, которая предполагает доступ из одного потока. Это гарантирует, что в поле всегда присутствует самое последнее значение.
Но я бы изменил твой цикл:
startSignal.WaitOne();
while(running)
{
//... some code
startSignal.WaitOne();
}
Как и в вашем посте, "некоторый код" может выполняться при остановке потока (т. Е. При вызове Stop), что является неожиданным и даже неправильным.
Булевы значения являются атомарными в C#, однако, если вы хотите изменить его в одном потоке и прочитать его в другом, вам нужно как минимум пометить его как volatile. В противном случае поток чтения может фактически прочитать его только один раз в регистр.
Логические значения атомарны в C#: http://msdn.microsoft.com/en-us/library/aa691278(VS.71).aspx
Кстати, я только что заметил эту часть кода:
// A method which runs in a thread
public void Run()
{
startSignal.WaitOne();
while(running)
{
startSignal.WaitOne();
//... some code
}
latch.Signal();
}
Вам нужно будет дважды разблокировать рабочий поток, используя "startSignal.Set()" для выполнения кода внутри блока while.
Это умышленно?