Я анализирую потоки с помощью ThreadSanitizer и получаю предупреждение, которое очень, очень запутывает мое понимание того, как работают мьютексы. Я использую gcc 6.3 на Debian Stretch.
В одном классе у меня есть:
auto MyPtr = std::make_shared<MyClass>(...);
В другом месте, которое называется другим потоком, у меня есть:
if(MyPtr.get()) {...}
ThreadSanitizer предупредил меня о состоянии гонки, и это здорово. Поэтому я исправил это следующим образом:
std::unique_lock<decltype(MyMutex)> lg(MyMutex); //MyMutex is std::mutex
auto MyPtr = std::make_shared<...>(...);
lg.unlock();
И другое место:
std::unique_lock<decltype(MyMutex)> lg(MyMutex);
if(MyPtr.get()) {...}
// mutex unlocks at the end of the function, which is like after another if-condition.
Теперь гонка данных ушла, и ThreadSanitizer сообщает, что Mutex разблокируется «дважды» …
WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread)
и это указывает на unlock()
вызов + конец другой функции.
Как мьютекс может быть разблокирован дважды? Может кто-нибудь объяснить?
Теперь, так как это вызвало у меня головную боль, я решил сделать это вместо:
std::shared_ptr<MyClass> MyPtr; //in the class definition
std::atomic_store(&MyPtr, std::make_shared<MyClass>(...));
И теперь я получаю жалобу на передачу данных:
WARNING: ThreadSanitizer: data race
Так я неправильно использую ThreadSanitizer? Может кто-нибудь объяснить, что здесь происходит?
Я никогда не понимал проблему мьютекса, но я смог избавиться от гонки данных с атомарностью, сделав другую загрузку атомарной:
if(std::atomic_load(&MyPtr).get()) {...}
Других решений пока нет …