Многопоточный код - порядок принудительного выполнения - PullRequest
3 голосов
/ 20 января 2009

У меня есть код, который будет доступен из двух потоков:


class Timer{
public:
   void Start(){
      start_ = clock_->GetCurrentTime();
      running_ = true;
   }

   void Read(){
      if(running_){
         time_duration remaining = clock_->GetCurrentTime() - start_;
         Actions(remaining)
      }
   }

private:
   void Actions(time_duration remaining);
   time start_;
   bool running;
};

Я посмотрел на некоторые другие таймеры, доступные в различных библиотеках, но не нашел ни одного, соответствующего моим требованиям, поэтому я сворачиваю свои собственные ...

Метод Start () вызывается (только один раз) из одного потока. Метод Read () вызывается очень быстро из другого потока, вызовы начнут поступать до вызова Start ().

Очевидно, что очень важно, чтобы переменная start_ была инициализирована до того, как установлен флаг running_. Эту проблему можно решить, добавив мьютекс, который захватывается при входе в метод Start () ... и захватывается перед проверкой running_ в методе Read () ... но это кажется несколько ненужным. Если все здесь выполняется по порядку, то проблем нет. У меня нет проблем с тем фактом, что Read () может произойти, когда другой поток находится в маршрутизации Start (), получая время от часов, например ... Read () происходит достаточно быстро, так что его большое дело

В любом случае, я искал способ гарантировать, что компилятор / процессор выполнит

  start_ = clock_->GetCurrentTime();
  running_ = true;

инструкции в порядке их перечисления выше. (Или если я пропускаю что-то еще).

Ответы [ 4 ]

3 голосов
/ 20 января 2009

Вам нужно сделать start_ и running_ volatile, а затем ввести барьер памяти между двумя назначениями в Start().

1 голос
/ 20 января 2009

Почему бы не избавиться от флага running и использовать, если переменная start пуста как условие? Вы не указываете язык, но какой-то изменчивый маркер для «начала» также будет хорошей идеей. Это также предполагает, что «начало» может быть написано атомарно. Например:

class Timer{
public:   
  void Start(){
    start_ = clock_->GetCurrentTime(); 
  }
  void Read(){
  if(nullptr != start_){
     time_duration remaining = clock_->GetCurrentTime() - start_;
     Actions(remaining)      
  }   
}
private:   
  void Actions(time_duration remaining);
  volatile time start_;
};
0 голосов
/ 20 января 2009

Почему бы просто не вставить

if (_running == false) Start();

В методе Read (). И либо защитите Start с мьютексом, либо определите его как "критический", чтобы обеспечить его однопоточность

0 голосов
/ 20 января 2009

Я не уверен, понимаю ли я ваш вопрос, но я думаю, что вы хотите предотвратить выполнение чтения, когда метод Start не был установлен (или не был выполнен полностью)?

Если это так, вы не можете решить свою проблему с помощью AutoResetEvent или ManualResetEvent (в зависимости от того, какое поведение вы хотите).

В методе Read вы можете указать, что метод Read должен ожидать, когда Auto / ManualResetEvent не был установлен, и в конце метода Start вы можете установить Event.

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