Предположим, я пишу класс семафоров C ++ с интерфейсом, который моделирует концепцию повышенной блокировки (т. Е. lock(); unlock(); try_lock();
и т. Д.). Безопасно / рекомендуется ли использовать форсированные блокировки для доступа RAII к такому объекту? Другими словами, предполагают ли повышающие блокировки (и / или другие связанные части библиотеки ускоряющих потоков), что концепция Lockable будет моделироваться только мьютексоподобными объектами, которые заблокированы и разблокированы из того же потока?
Я предполагаю, что можно использовать семафор в качестве модели для Lockable. Я просмотрел некоторые из источников повышения, и это "кажется" хорошо. Блокировки не содержат явных ссылок на this_thread или что-то подобное. Более того, концепция Lockable не имеет функции, подобной whichThreadOwnsMe()
. Похоже, я даже смог бы передать ссылку boost::unique_lock<MySemaphore>
на boost::condition_variable_any::wait
. Тем не менее, документация не совсем ясно о требованиях.
Чтобы проиллюстрировать, что я имею в виду, рассмотрим класс двоичных семафоров «голые кости» по следующим строкам:
class MySemaphore{
bool locked;
boost::mutex mx;
boost::condition_variable cv;
public:
void lock(){
boost::unique_lock<boost::mutex> lck(mx);
while(locked) cv.wait(lck);
locked=true;
}
void unlock(){
{
boost::lock_guard<boost::mutex> lck(mx);
if(!locked) error();
locked=false;
}
cv.notify_one();
}
// bool try_lock(); void error(); etc.
}
Теперь предположим, что где-то, на объекте или глобально, у меня есть
MySemaphore sem;
Я хочу заблокировать и разблокировать его с помощью RAII. Также я хочу иметь возможность «передать» владение блокировкой из одного потока в другой. Например, в одном потоке я выполняю
void doTask()
{
boost::unique_lock<MySemaphore> lock(sem);
doSomeWorkWithSharedObject();
signalToSecondThread();
waitForSignalAck();
lock.release();
}
Пока другой поток выполняет что-то вроде
{
waitForSignalFromFirstThread();
ackSignal();
boost::unique_lock<MySemaphore>(sem,boost::adopt_lock_t());
doMoreWorkWithSameSharedObject();
}
Причина, по которой я это делаю, заключается в том, что я не хочу, чтобы кто-либо еще мог установить блокировку на sem
между временем выполнения первого потока doSomeWorkWithSharedObject()
и временем выполнения второго doMoreWorkWithSameSharedObject()
, По сути, я делю одну задачу на две части. И причина, по которой я делю задачу, состоит в том, что (1) я хочу, чтобы первая часть задачи началась как можно скорее, (2) я хочу гарантировать, что первая часть завершена до того, как doTask () вернется, и (3) я хочу, чтобы вторая, более трудоемкая часть задачи была выполнена другим потоком, возможно, выбранным из пула подчиненных потоков, которые ожидают завершения задач, которые были запущены мастер-потоками.
ПРИМЕЧАНИЕ: я недавно опубликовал этот же вопрос (вроде) здесь Повышение моделирования :: Блокируется семафором, а не мьютексом (ранее назывался: разблокировка мьютекса из другого потока)
но я перепутал мьютексы с семафорами, и поэтому вопрос об использовании буст-блокировок действительно не был решен.