Почему в C ++ 0x или Boost.Thread нет блокированных замков для нескольких мьютексов? - PullRequest
6 голосов
/ 02 мая 2010

C ++ 0x библиотека потоков или Boost.thread определяют не-членную переменную шаблонную функцию, которая блокирует все блокировки, избегая мертвых блокировок.

template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);

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

{
  std::lock(l1,l2);
  // do some thing
  // unlock li l2 exception safe
}

Это означает, что нам нужно использовать другой механизм в качестве блока try-catch, чтобы сделать безопасный код для исключения или определить нашу собственную блокировку области действия для нескольких мьютексов или даже сделать это

{
  std::lock(l1,l2);
  std::unique_lock lk1(l1, std::adopted);
  std::unique_lock lk2(l2, std::adopted);
  // do some thing
  // unlock li l2 on destruction of lk1 lk2
}

Почему стандарт не включает блокировку по объему для нескольких мьютексов одного типа, например,

{
  std::array_unique_lock<std::mutex> lk(l1,l2);
  // do some thing
  // unlock l1 l2 on destruction of lk
}

или кортежи мьютексов

{
  std::tuple_unique_lock<std::mutex, std::recursive_mutex> lk(l1,l2);
  // do some thing
  // unlock l1 l2 on destruction of lk
}

Что-то не так в дизайне?


Обновлено: описание из стандарта

template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);

Требуется : каждый тип параметра шаблона должен соответствовать требованиям Mutex, за исключением того, что вызов try_-lock () может вызвать исключение. [Примечание: шаблон класса unique_lock удовлетворяет этим требованиям, когда создается соответствующий экземпляр. —Конечная записка]

Эффекты : Все аргументы блокируются с помощью последовательности вызовов lock (), try_lock () или unlock () для каждого аргумента. Последовательность вызовов не должна приводить к тупику, но в остальном не указана. [Примечание: должен использоваться алгоритм предотвращения тупиков, такой как попытка и откат, но конкретный алгоритм не указан, чтобы избежать чрезмерных ограничений реализации. - end note] Если вызов lock () или try_lock () вызывает исключение, unlock () должен вызываться для любого аргумента, заблокированного вызовом lock () или try_lock ().


Я принял ответ. Я понимаю, что главная причина в том, что нет времени, чтобы улучшить библиотеку C ++ 0x Thread. Я надеюсь, что TR2 будет включать в себя гораздо больше вещей.

Ответы [ 2 ]

3 голосов
/ 02 мая 2010

Я думаю, что, предоставляя defer_lock_t (и accept_lock_t), вы ожидаете, что использование будет таким же, как ваш второй пример, или, вероятно, больше похоже на:

 std::unqiue_lock ul1(l1, std::deferred);
 std::unique_lock ul2(l2, std::deferred);
 std::lock(ul1, ul2);

Это исключительная безопасность и все такое хорошее.

Я, конечно, не могу притворяться, что знаю умы дизайнеров, но я предполагаю, что они прилагают усилия для обеспечения минимального набора портативных, безопасных примитивов. Тип блокировки с несколькими областями видимости - это так много обледенения, и это обледенение, что, если в стандарте необходимо указать и спроектировать, или в boost.thread, обледенение, которое необходимо реализовать (и, конечно, в конечном счете, стандарт должен быть обеспокоен реализация тоже, посмотри что получилось с экспортом).

0 голосов
/ 02 мая 2010

Построение одного объекта, который блокирует несколько блокировок, не предотвращает любые взаимоблокировки больше, чем блокировка их по отдельности. Вы не можете заблокировать две блокировки одновременно ... если вы не используете две нити, что побеждает точку. Это справедливо, даже если вы поместите их в одно и то же утверждение.

...