Использовать мьютекс как семафор? - PullRequest
13 голосов
/ 24 июля 2011

Мне нужны два потока для продвижения по шаблону "tick tock" . При использовании семафора это выглядит хорошо:

Semaphore tick_sem(1);
Semaphore tock_sem(0);

void ticker( void )
{
   while( true )
   {
      P( tick_sem );
      do_tick();
      V( tock_sem );
   }
}

void tocker( void )
{
   while( true )
   {
      P( tock_sem );
      do_tock();
      V( tick_sem );
   }
}

Однако, если я делаю то же самое с мьютексом (который технически является двоичным семафором), он имеет странный запах кода.

std::mutex tick_mutex;
std::mutex tock_mutex;
tock_mutex.lock();

void ticker( void )
{
   while( true )
   {
      tick_mutex.lock();
      do_tick();
      tock_mutex.unlock();
   }
}

void tocker( void )
{
   while( true )
   {
      tock_mutex.lock()
      do_tock();
      tick_mutex.unlock();
   }
}

Я думаю, что запах в том, что мьютекс не предназначен для передачи информации другому потоку. (Комитет по стандартизации c ++ 11 добавил ложную ошибку try_lock для предотвращения неожиданной передачи информации; §30.4.1 / 14.) Кажется, что мьютексы предназначены для синхронизации доступа к переменной, которая затем может передавать информацию в другой поток.

Наконец, когда реализовано с std::condition_variable, это выглядит правильно, но это более сложно (переменная tick_vs_tock, мьютекс и условная переменная). Я опустил реализацию для краткости, но это действительно просто.

В порядке ли решение мьютекса? Или в этом что-то не так?

Есть ли хороший шаблон для решения моей проблемы тика / токса, о котором я не задумывался?

Ответы [ 2 ]

12 голосов
/ 24 июля 2011

Mutex - это не просто бинарный семафор, он также имеет ограничение, что только блокирующий поток может его разблокировать.

Вы нарушаете это правило.

Edit:

С MSDN :

Функция ReleaseMutex завершается ошибкой, если вызывающий поток не владеет объект мьютекса.

С какого-то сайта, который Google открыл для pthread_mutex_unlock :

Функция pthread_mutex_unlock () может завершиться ошибкой, если:

EPERM Текущему потоку не принадлежит мьютекс.

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

10 голосов
/ 24 июля 2011

Поскольку у вас есть пример использования семафора, я думаю, что исправление заключается в переносе реализации одного с использованием мьютекса и переменной условия .

Это может быть не особенно эффективноон будет использовать пару мьютекс / condvar на семафор), но вы можете включить альтернативную реализацию в системах, которые имеют свои собственные семафоры (такие как Posix и Windows).подверженные ошибки ".При всем уважении к Boost, я думаю, что по крайней мере некоторые из нас могут справиться.Конечно, вы можете связать себя узлами , пытаясь делать сложные вещи с несколькими семафорами , и они являются довольно низкоуровневым инструментом.Но когда они правильные, нет проблем.

...