Как упражнение для обучения, я просто пытаюсь сделать класс Semaphore
, используя std::mutex
и несколько других вещей, предоставляемых стандартом C++. Мой семафор должен при необходимости использовать столько readLock()
, но writeLock()
может быть приобретен только после того, как все чтения будут разблокированы.Реализация Семафора с std :: mutex
//Semaphore.h
#include <mutex>
#include <condition_variable>
class Semaphore{
public:
Semaphore();
void readLock(); //increments the internal counter
void readUnlock(); //decrements the internal counter
void writeLock(); //obtains sole ownership. must wait for count==0 first
void writeUnlock(); //releases sole ownership.
int count; //public for debugging
private:
std::mutex latch;
std::unique_lock<std::mutex> lk;
std::condition_variable cv;
};
//Semaphore.cpp
#include "Semaphore.h"
#include <condition_variable>
#include <iostream>
using namespace std;
Semaphore::Semaphore() : lk(latch,std::defer_lock) { count=0; }
void Semaphore::readLock(){
latch.lock();
++count;
latch.unlock();
cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::readUnlock(){
latch.lock();
--count;
latch.unlock();
cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::writeLock(){
cv.wait(lk,[this](){ return count==0; }); //why can't std::mutex be used here?
}
void Semaphore::writeUnlock(){
lk.unlock();
cv.notify_all();
}
Моя тестовая программа writeLock()
семафор, начать пучок нитей, а затем освободить семафор. Сразу же после этого основной поток снова попытается снова сфотографировать writeLock()
. Идея заключается в том, что когда семафор становится разблокированным, потоки будут readLock()
и не будут препятствовать тому, чтобы основной поток ничего не делал, пока все не закончили. Когда они все закончат и выпустят семафор, основной поток может снова получить доступ. Я понимаю, что это может случиться не обязательно, но это один из случаев, который я ищу.
//Main.cpp
#include <iostream>
#include <thread>
#include "Semaphore.h"
using namespace std;
Semaphore s;
void foo(int n){
cout << "Thread Start" << endl;
s.readLock();
this_thread::sleep_for(chrono::seconds(n));
cout << "Thread End" << endl;
s.readUnlock();
}
int main(){
std::srand(458279);
cout << "App Launch" << endl;
thread a(foo,rand()%10),b(foo,rand()%10),c(foo,rand()%10),d(foo,rand()%10);
s.writeLock();
cout << "Main has it" << endl;
a.detach();
b.detach();
c.detach();
d.detach();
this_thread::sleep_for(chrono::seconds(2));
cout << "Main released it" << endl;
s.writeUnlock();
s.writeLock();
cout << "Main has it " << s.count << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "Main released it" << endl;
s.writeUnlock();
cout << "App End" << endl;
system("pause"); //windows, sorry
return 0;
}
Программа выдает исключение, в котором говорится: «Разблокировка неумелого мьютекса». Я думаю, что ошибка находится в writeLock()
или writeUnlock()
, но я не уверен. Может кто-то указать мне верное направление?
EDIT: при инициализации lk
в конструкторе отсутствовал std::defer_lock
, однако он не исправил ошибку, которую я получал. Как упоминалось в комментарии, это не семафор, и я извиняюсь за путаницу. Чтобы подтвердить эту проблему, вот вывод, что я получаю (вещи в скобках только мои комментарии, а не на самом деле на выходе):
App Launch
Thread Start
Thread Start
Main has it
Thread Start
Thread Start
Thread End (what?)
Main released it
f:\dd\vctools\crt_bld\self_x86\crt\src\thr\mutex.c(131): unlock of unowned mutex
Thread End
Thread End
Thread End
Похоже, вы описываете «блокировку читателя-писателя», а не более общий «семафор». –
@CoryNelson Я думаю, что вы правы, но есть ли тонкий намек на решение из этого комментария, который мне не хватает, или это просто семантика? – Suedocode
Решение проблемы. Вы хотите реализовать семафор или блокировку чтения-записи? –