что если notify () вызывается до wait ()?

У меня есть ситуация, когда notify () может быть вызван перед wait ().

Я пытаюсь создать симулятор для планирования следующего события, когда я «уведомляю» его, отправляя ему сообщения. Поэтому я разработал цепочку ожидания-> уведомления-> расписания

void Broker::pause()
{
boost::unique_lock<boost::mutex> lock(m_pause_mutex);
{
std::cout << "pausing the simulation" << std::endl;
m_cond_cnn.wait(lock);
std::cout << "Simulation UNpaused" << std::endl;
// the following line causes the current function to be called at
// a later time, and a notify() can happen before the current function
// is called again
Simulator::Schedule(MilliSeconds(xxx), &Broker::pause, this);
}
}

void Broker::messageReceiveCallback(std::string message) {
boost::unique_lock<boost::mutex> lock(m_pause_mutex);
{
m_cond_cnn.notify_one();
}
}

проблема здесь в том, что: могут быть ситуации, когда notify () вызывается перед вызовом wait ().

Есть ли выход для такой ситуации?
благодарю вас

8

Решение

Переменные условия вряд ли могут использоваться отдельно, хотя бы потому, что, как вы заметили, они пробуждают только ожидающие в настоящий момент потоки. Существует также проблема ложных пробуждений (т. Е. Переменная условия может иногда пробуждать поток без какого-либо соответствующего notify будучи призванным). Для правильной работы условным переменным обычно требуется другая переменная для поддержания более надежного состояния.

Чтобы решить обе эти проблемы, в вашем случае вам просто нужно добавить логический флаг:

boost::unique_lock<boost::mutex> lock(m_pause_mutex);
while (!someFlag)
m_cond_cnn.wait(lock);
someFlag = false;

//...

boost::unique_lock<boost::mutex> lock(m_pause_mutex);
someFlag = true;
m_cond_cnn.notify_one();
9

Другие решения

Я думаю, что ответ syam в целом хорош, но в вашем конкретном случае, когда вы, похоже, используете ns-3, я бы предложил вместо этого реструктурировать свой код для использования правильных примитивов в ns-3:

  1. Я подозреваю, что вы используете одну из реализаций симулятора реального времени ns-3. Хорошо.
  2. Запланируйте событие keeplive на 0,1 с, чтобы убедиться, что симулятор продолжает работать (он запустится, когда не останется никаких событий).
  3. При желании используйте логическое значение в этом событии keepalive, чтобы проверить, следует ли перенести событие keepalive или вызвать Simulator :: Stop.
  4. Создайте поток для запуска главного цикла симулятора с помощью Simulator :: Run (). Симулятор будет спать до тех пор, пока не истечет срок действия следующего запланированного события или пока не будет запланировано новое событие
  5. Используйте Simulator :: ScheduleWithContext, чтобы запланировать событие извне из другого потока.

Имейте в виду, что API ns-3 не потокобезопасен в целом. Единственный API ns-3, который является потокобезопасным, это ns3 :: Simulator :: ScheduleWithContext. Я не могу подчеркнуть, насколько важно не использовать любой другой API, доступный в пространстве имен ns-3 :: из потока, который не является основным потоком.

1

По вопросам рекламы [email protected]