2017-01-22 1 views
0

boost :: atomic имеет функцию хранения и загрузки функции. Однако есть функция, которая может возвращать и текущее значение и устанавливать значение в одно и то же время, что означает, что две операции являются атомарными.активировать атомную нагрузку и хранить в то же время

После кода является проблемой

void Initialize() 
{ 
    ///if some other thread is initializing, skip this step 
    if (m_initializing.load(boost::memory_order_relaxed)) 
     return S_FALSE; 

    m_initializing.store(true, boost::memory_order_relaxed); 
    return S_OK; 
} 

Если два потока вызывает эту функцию инициализации одновременно. поток A и B набирают нагрузку и возвращают false, они будут вызывать хранилище одновременно. Поэтому я хочу атомную функцию. если A обнаруживает, что m_initializing является ложным и одновременно устанавливается значение true. так что поток B знает, что на нем работает поток.

+0

«загрузка и хранение в одно и то же время» называется обмен – harold

+0

Большое спасибо. Я нахожу это – ernst

ответ

0

Ваш подход сложнее, чем кажется на первый взгляд.

Как указано в разделе комментариев, ридовского-Modify-Write (МРО) exchange(), который заменяет load() может решить проблему нескольких потоков, имеющих доступ к той же области, , но то, что вы ожидаете другой поток будет делать в то время как инициализация еще не завершена? В конце концов, ваш флаг указывает, что запущена процедура инициализации, а не завершена. Кроме того, использование memory_order_relaxed не дает никаких гарантий, что инициализированные данные правильно синхронизированы с другими потоками, вызывающими Initialize(). По крайней мере, вам нужно будет использовать семантику получения/выпуска, но поскольку флаг (с exchange()) теперь установлен в начале, он еще ничего не выпускает.

Гораздо проще использовать mutex, который обеспечивает как сериализацию потоков, так и синхронизацию между потоками. Кроме того, используйте флаг, указывающий статус initialized.

bool m_initialized{false}; 
boost::mutex m_mut; 

void Initialize() 
{ 
    boost::lock_guard<boost::mutex> lck{m_mut}; 

    if (m_initialized) 
     return; // already initialized 

    // ... initializing part 

    m_initialized = true; 

    return; 
} 

Поскольку mutex синхронизирует все в защищенной зоне, m_initialized теперь может быть регулярным bool (если он не используется также в другом месте).

Я хотел бы предложить, чтобы заменить boost параллелизм примитивы (mutex, atomic) с std. Они были приняты стандартом от boost и доступны с C++ 11

+0

Мне интересно, если шаг инициализации занимает много времени, тогда другой поток блокируется. И небезопасно вызывать функцию под защитой мьютекса, что может вызвать тупик неожиданно. – ernst

+0

Можете ли вы дать больше объяснений о memory_order_relaxed, семантике получения/выпуска. Я действительно не могу понять документацию о порядке памяти. – ernst

+0

@ernst Инициализация может занять некоторое время, но обычно другие потоки ничего не могут сделать до завершения инициализации; хотя трудно сказать, поскольку эта часть контекста отсутствует. Тупик невозможен, если вы используете мьютекс, как показано здесь, пока вы не вызываете функцию Initialize() 'рекурсивно. – LWimsey

Смежные вопросы