C++ 仅使用互斥锁的读/写锁实现?
我试图只使用互斥锁实现读/写锁(只是为了学习)。正当我认为我已经涵盖了所有的角落案例(因为程序使用了各种组合),我意识到,我忽略了一个事实(因为它在ubuntu中工作),即互斥应该由线程的所有者释放。下面是我的实现C++ 仅使用互斥锁的读/写锁实现?,c++,multithreading,pthreads,mutex,C++,Multithreading,Pthreads,Mutex,我试图只使用互斥锁实现读/写锁(只是为了学习)。正当我认为我已经涵盖了所有的角落案例(因为程序使用了各种组合),我意识到,我忽略了一个事实(因为它在ubuntu中工作),即互斥应该由线程的所有者释放。下面是我的实现 class rw_lock_t{ int NoOfReaders; int NoOfWriters, NoOfWritersWaiting; pthread_mutex_t class_mutex; pthread_cond_t class_cond
class rw_lock_t{
int NoOfReaders;
int NoOfWriters, NoOfWritersWaiting;
pthread_mutex_t class_mutex;
pthread_cond_t class_cond;
pthread_mutex_t data_mutex;
public:
rw_lock_t()
: NoOfReaders(0),
NoOfWriters(0), NoOfWritersWaiting(0)
{
pthread_mutex_init(&class_mutex, NULL);
pthread_mutex_init(&data_mutex, NULL);
pthread_cond_init(&class_cond, NULL);
}
void r_lock()
{
pthread_mutex_lock(&class_mutex);
//while(NoOfWriters!=0 || NoOfWritersWaiting!=0) //Writer Preference
while(NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
if(NoOfReaders==0)
{
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
else if(NoOfReaders>0) //Already Locked
{
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
}
void w_lock()
{
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting++;
while(NoOfReaders!=0 && NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting--; NoOfWriters++;
pthread_mutex_unlock(&class_mutex);
}
void r_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfReaders--;
if(NoOfReaders==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
void w_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfWriters--;
if(NoOfWriters==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
};
我现在的问题是,什么是最好的纠正方法(最小的改变)。信号量绝对是空闲的选择,但我认为解决方案如下
解决方案#1
1) 我将有一个专用的线程,只是为了锁定/解锁互斥锁的读取情况
2) 此线程将等待一个条件变量以从r_lock或r_unlock获取信号
3) r_lock和r_unlock将代替执行“pthread_mutex_lock/unlock(&data_mutex);”,而是向要锁定的专用线程发送信号
4) 我必须记住很多关于这个实施的事实
class rw_lock_t{
int NoOfReaders;
int NoOfWriters, NoOfWritersWaiting;
pthread_mutex_t class_mutex;
pthread_cond_t class_cond;
pthread_mutex_t data_mutex;
public:
rw_lock_t()
: NoOfReaders(0),
NoOfWriters(0), NoOfWritersWaiting(0)
{
pthread_mutex_init(&class_mutex, NULL);
pthread_mutex_init(&data_mutex, NULL);
pthread_cond_init(&class_cond, NULL);
}
void r_lock()
{
pthread_mutex_lock(&class_mutex);
//while(NoOfWriters!=0 || NoOfWritersWaiting!=0) //Writer Preference
while(NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
if(NoOfReaders==0)
{
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
else if(NoOfReaders>0) //Already Locked
{
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
}
void w_lock()
{
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting++;
while(NoOfReaders!=0 && NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting--; NoOfWriters++;
pthread_mutex_unlock(&class_mutex);
}
void r_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfReaders--;
if(NoOfReaders==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
void w_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfWriters--;
if(NoOfWriters==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
};
- 信令和实际锁定是两个不同的事件,因此可能需要同步
- 将需要一个互斥+condVariable+线程和更多额外的同步
那么,是否有更好的方法来纠正程序。您不需要单独的互斥“数据”;如果内部逻辑正确,整个构造将充当数据锁。相反,您可以为读卡器和写卡器使用两个单独的条件变量,以便可以广播所有等待的读卡器,而不会影响等待的写卡器。代码如下;您还可以看到,这种方式更简单。此外,我添加了一个析构函数并修复了w|u lock中的一个bug:等待的条件应该是
(NoOfReaders!=0 | | NoOfWriters!=0)
,而不是&&
class rw_lock_t {
int NoOfReaders;
int NoOfWriters, NoOfWritersWaiting;
pthread_mutex_t class_mutex;
pthread_cond_t reader_gate;
pthread_cond_t writer_gate;
public:
rw_lock_t()
: NoOfReaders(0), NoOfWriters(0), NoOfWritersWating(0),
class_mutex(PTHREAD_MUTEX_INITIALIZER),
reader_gate(PTHREAD_COND_INITIALIZER),
writer_gate(PTHREAD_COND_INITIALIZER)
{}
~rw_lock_t()
{
pthread_mutex_destroy(&class_mutex);
pthread_cond_destroy(&reader_gate);
pthread_cond_destroy(&writer_gate);
}
void r_lock()
{
pthread_mutex_lock(&class_mutex);
//while(NoOfWriters>0 || NoOfWritersWaiting>0) //Writer Preference
while(NoOfWriters>0)
{
pthread_cond_wait(&reader_gate, &class_mutex);
}
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
void w_lock()
{
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting++;
while(NoOfReaders>0 || NoOfWriters>0)
{
pthread_cond_wait(&writer_gate, &class_mutex);
}
NoOfWritersWaiting--; NoOfWriters++;
pthread_mutex_unlock(&class_mutex);
}
void r_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfReaders--;
if(NoOfReaders==0 && NoOfWritersWaiting>0)
pthread_cond_signal(&writer_gate);
pthread_mutex_unlock(&class_mutex);
}
void w_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfWriters--;
if(NoOfWritersWaiting>0)
pthread_cond_signal(&writer_gate);
//else //Writer Preference - don't signal readers unless no writers
pthread_cond_broadcast(&reader_gate);
pthread_mutex_unlock(&class_mutex);
}
};
类读写锁{
互斥写锁;
互斥读锁;
整数读取计数;
公众:
ReadWriteLock(){
读取计数=0;
}
void LockWrite(){
writeLock.lock();
}
void UnlockWrite(){
writeLock.unlock();
}
void LockRead(){
锁\防护锁(读锁);
++重新计数;
如果(1==读取计数){
LockWrite();
}
}
void UnlockRead(){
锁\防护锁(读锁);
--重新计数;
如果(0==读取计数){
解锁写入();
}
}
};
正如Alexey指出的,如果最后一个要解锁写入的读线程不是第一个要锁定写入的读线程,那么行为是未定义的。看见
std::mutex::unlock
Windows释放互斥体:使用条件,它不仅仅是互斥体。这是一个完美的答案。请不要做作业!我们不应该在r_lock()和w_lock()函数中检查虚假的唤醒条件吗?这来自于手册页:“当使用条件变量时,始终存在一个布尔谓词,该谓词涉及与每个条件等待相关联的共享变量,如果线程应该继续,则该谓词为true。可能会从pthread_cond_timedwait()或pthread_cond_wait()函数中发生虚假唤醒。因为从pthread_cond_timedwait()返回或者pthread_cond_wait()并不意味着与此谓词的值有关的任何内容,应在此类返回时重新计算谓词。“-->如果为false,请返回到循环@cforfun,这已经在代码中完成了,因为pthread_cond_wait()在检查条件的循环中使用。@CppNoob,在这段代码中,广播是无条件的,可以在解锁互斥锁后完成。然而,这两个信号都需要某些条件才能为真。这些条件检查由互斥锁保护的rwlock状态,以防止并发访问。如果将这些检查移出互斥锁保护,则会在代码中创建竞争条件,从而导致未定义的行为。存在一个问题,即解除写入互斥锁的最后一个读卡器线程可能与锁定写入互斥锁的第一个读卡器线程不同。对于
std::mutex
,这是不允许的-调用unlock()的线程应该拥有mutex。Alexey,你说得对。因此,我可以得到的解决方案与您的一样,是针对posix的cv.mutex unlock:pthread_mutex_unlock: