2017-01-30 9 views
2

Я пишу многопоточный класс сокетов. Функция BelowBounds() может быть вызвана из нескольких потоков одновременно, мне нужно предотвратить использование мьютексов. Этот код является потокобезопасным?Является ли атомное увеличение и сравнение потокобезопасным

class UDPSocketHT 
{ 
public: 
    std::atomic<size_t> m_nSimultaneousRecvCalls; 
    std::atomic<size_t> m_nPendingOperations; 
    //... 
    bool UDPSocketHT::BelowBounds () 
    { 
     return (!m_nSimultaneousRecvCalls || (m_nPendingOperations + 1 <= m_nSimultaneousRecvCalls)) ? true : false; 
    } 
} 

Или я должен написать таким образом?

bool UDPSocketHT::BelowBounds () 
{ 
    size_t x = m_nSimultaneousRecvCalls; 
    size_t y = m_nPendingOperations; 
    return (!x || (y + 1 <= x)) ? true : false; 
} 
+1

Не связанный с вашим вопросом, но если у вас есть тернарное выражение, приводящее к «истинному» или «ложному», на самом деле нет необходимости в тройном выражении. В вашем последнем примере вы могли бы также написать 'return! X || (y + 1 <= x); ' –

ответ

5

Оба из ваших альтернатив являются небезопасными. Каждая атомная переменная сама по себе является атомарной, но использование двух из них в одном утверждении не является.

Вы можете обернуть свою проверку в мьютексе или создать способ использования одного атома.

Какие операции на std::atomic являются атомными?

  • operator= хранит новое значение атомарно

  • load() или operator T (с использованием в выражении) считывает значение атомарно

  • operator++ увеличивает значение атомарно

  • compare_exchange_weak/strong проверка и установить значение атомарно

  • more details

Использования двух Atomics в выражении не является атомарным: a + b прочтет a атомарно, затем чтение b атомарны, но все, что может произойти между чтением a и b; к тому моменту, когда вы прочитали b, a уже может иметь другое значение.