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