Как инициализировать глобальный мьютекс C ++ потокобезопасным способом - PullRequest
0 голосов
/ 30 ноября 2018

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

void Initialize()
{
  static Mutex L;   // can't be initialized at compile time because constructor calls CreateMutex()
  L.Lock()
  // call thread unsafe code
  L.Unlock()
}

Вот уже рассмотренные решения:

  1. Объявите Mutex в глобальной области видимости, чтобыинициализация происходит перед main ().К сожалению, это не работает, когда есть глобальная переменная, чей конструктор вызывает Initialize (), потому что в C ++ нет гарантии того, что глобальные переменные порядка инициализируются

  2. Использование атомарных операций

void Initialize() { static volatile uint16_t lock=0; // trivial initialization can happen @ compile time while (AtomicExchange(lock,(uint16_t)1)!=0); // swap lock with 1 and return previous value // call thread unsafe code lock=0; }

Это работает, но имеет недостаток - занятое ожидание

Использовать инициализатор времени компиляции pthread

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

К сожалению, это для Windows, и мы стараемся избегать использования pthread

Оцените решение, портативное .Я знаю, что в C ++ 2011 статическая инициализация функции является поточно-ориентированной, но мы избегаем C ++ 2011, потому что некоторые встроенные платформы могут иметь ненадежную поддержку C ++ 2011.

1 Ответ

0 голосов
/ 18 марта 2019

IMO решение вашей проблемы - использовать отличную идиому счетчика.Эта идиома очень хорошо описана здесь: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter.

При использовании этой идиомы std::cout, std::cerr, std::clog потоки инициализируются.Единственное требование - вам нужно правильно рассчитать выравнивание созданного типа.Используя это выравнивание, вам нужно создать глобальный буфер.Используя этот буфер, можно создать экземпляр нужного типа с оператором размещения new.Boost и Modern C ++ (> = C ++ 11) имеют (std|boost)::aligned_storage шаблонные классы для создания правильно выровненного буфера для вас.Пожалуйста, обратитесь к:

В современных версиях C ++ есть оператор alignof, который можно использовать длярассчитать выравнивание определенного типа.В boost вы должны использовать черту типа alignment_of: https://www.boost.org/doc/libs/1_69_0/libs/type_traits/doc/html/boost_typetraits/reference/alignment_of.html. alignment_of. Черта типа также является частью STL в современном C ++, но в этом конкретном случае оператор alignof проще использовать.

...