Мне было интересно, что произойдет, когда вы переместите unique_lock
, который содержит recursive_mutex
.Перемещение уникального_блока <recursive_mutex> в другой поток
В частности, я смотрел на этот код:
recursive_mutex g_mutex;
#define TRACE(msg) trace(__FUNCTION__, msg)
void trace(const char* function, const char* message)
{
cout << std::this_thread::get_id() << "\t" << function << "\t" << message << endl;
}
future<void> foo()
{
unique_lock<recursive_mutex> lock(g_mutex);
TRACE("Owns lock");
auto f = std::async(launch::async, [lock = move(lock)]{
TRACE("Entry");
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
this_thread::sleep_for(chrono::seconds(3));
});
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Doesn't own lock!
return f;
}
int main()
{
unique_lock<recursive_mutex> lock(g_mutex);
TRACE("Owns lock");
auto f = foo();
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
f.wait();
TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock!
}
Выход этого образца кода удивил меня много. Как unique_lock
в main() знает, что поток выпустил мьютекс? Это реально?
Непонятно, что вы находите удивительным. В 'unique_lock' имеется простой логический элемент' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' 'owns_lock()' не касается базового мьютекса. Сказав это, ваша программа проявляет неопределенное поведение: когда 'unique_lock' уничтожается в рабочем потоке, он вызывает' g_mutex.unlock() ', но рабочий поток не имеет блокировки на' g_mutex' (который является pre -requisite для 'unlock()'). –
@IgorTandetnik Спасибо. Таким образом, невозможно переместить право собственности на 'recursive_mutex' между потоками? Что делать, если мьютекс не был рекурсивным? Будет ли перемещение 'unique_lock' действительно перемещать право собственности на поток владельца? –
Перемещение 'unique_lock' между потоками абсолютно не подходит для вас. Поймите, что 'unique_lock' - не что иное, как указатель' mutex * 'и флаг 'bool owns' - черной магии нет. Конструктор перемещения просто перемещается по этому указателю и является логическим. Вызов 'my_mutex.unlock()' в потоке, отличном от того, который называется 'my_mutex.lock()', демонстрирует неопределенное поведение, независимо от того, сделано оно явно или косвенно, обманом 'unique_lock'. Это относится ко всем вкусам мьютексов. –