Как передать право собственности на объект синхронизации в C++ или Winapi?

Можно ли передать право собственности на мьютекс, критическую секцию и т. д. от первого потока второму потоку, не позволяя тем временем какому-либо третьему потоку захватить право собственности? документация по критической секции запрещает вызывать LeaveCriticalSection в потоке, отличном от того, который вызвал EnterCriticalSection:

Если поток вызывает LeaveCriticalSection, когда он не владеет указанным объектом критической секции, возникает ошибка, которая может привести к тому, что другой поток, использующий EnterCriticalSection, будет ожидать бесконечно.

Но в моем сценарии мне нужно точно освободить объект синхронизации в потоке, отличном от того, который его получил, чтобы ни один другой (третий) поток не мог получить право собственности на объект синхронизации в то же время (с момента получения первый поток до момента освобождения вторым потоком). Для моих нужд подойдет решение с потоковой передачей C++ или вызовами WinAPI.


person Serge Rogatch    schedule 10.11.2015    source источник
comment
std::move не должно работать?   -  person deW1    schedule 10.11.2015
comment
@deW1 CiriticalSection — это объект ОС Windows, а не класс C++.   -  person Devolus    schedule 10.11.2015
comment
Вы можете сделать это со вторым критическим разделом (или другим объектом синхронизации), который защищает передачу между ними. Однако трудно получить правильное решение без риска взаимоблокировок. Вы уверены, что вам нужно это сделать?   -  person Jonathan Potter    schedule 10.11.2015
comment
@deW1, std::mutex нельзя скопировать или переместить с en.cppreference.com/w /cpp/поток/мьютекс . Кроме того, std::move предназначен для перемещения объектов в памяти, а не для перемещения объектов синхронизации между потоками. Например. unique_lock является подвижным (в памяти с std::move, но, похоже, не позволяет перемещать мьютекс между потоками).   -  person Serge Rogatch    schedule 10.11.2015
comment
В ваших сообщениях есть несколько неясных моментов, но если бы мне пришлось угадывать, я думаю, что вы ищете объект события win32. Вы можете подождать и установить событие из другого потока. Если нет, то уточните, пожалуйста, в каком состоянии поток, который приобрел раздел, и почему он не может освободить критический раздел? Откуда вы знаете, что этот поток не находится в середине возможного состояния гонки, для предотвращения которого предназначена критическая секция?   -  person Jonathan    schedule 10.11.2015
comment
@JonathanPotter, я не вижу простого способа сделать это со вторым критическим разделом. Первому потоку по-прежнему необходимо покинуть первую критическую секцию, а второму потоку по-прежнему необходимо войти в первую критическую секцию. Так кто же будет владеть вторым критическим участком, когда в него войдут и когда покинут?   -  person Serge Rogatch    schedule 10.11.2015
comment
But in my scenario I need to exactly release the synchronization object in a different thread than the one who acquired it - Критическая секция просто не предназначена для такого использования. Вы можете использовать другой механизм синхронизации, например, semaphore: у него нет семантики ownership, поэтому он может быть освобожден любым потоком.   -  person Tsyvarev    schedule 10.11.2015
comment
@Jonathan, да, в этом сценарии событие с автоматическим сбросом кажется более подходящим: первый поток ожидает события, после того, как этот поток получает событие, никто другой также не может его получить, затем первый поток передает дескриптор события в второй поток, и после того, как второй поток выполнит работу, он может освободить событие (вернуть его в сигнальное состояние).   -  person Serge Rogatch    schedule 10.11.2015


Ответы (1)


Нет, передача владения потоком не поддерживается. Более того, я твердо верю, что любой дизайн, который зависит от владения замком, ошибочен и вызовет проблемы в будущем.

Однако, если передача права собственности требуется только для снятия блокировки из потока, отличного от того, который ее получает, у вас есть два варианта:

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

Неопределенное поведение

Освобождение мьютекса из потока, которому он не принадлежит, не определено. Тем не менее, вы можете закодировать свое приложение с их помощью. Проблема, с которой вы столкнетесь, заключается в том, что синхронизация данных может не происходить на когерентных чипах без кэша, если поток, блокирующий мьютекс, выполнялся на одном процессоре, а разблокировка происходит на другом. В результате данные, которые не были защищены другой синхронизацией, будут «грязными». Однако, если таких данных нет — например, мьютекс действительно используется в качестве «семафора» и не защищает никакие данные — это может быть приемлемо.

person SergeyA    schedule 10.11.2015