Table of Contents
此博客是关于一篇信号量的文章,信号量提供进程间互斥,很方便。用mutex来实现信号量的功能,必须将mutex建立在共享内存上才能实现。所以当需要线程间互斥的时候,最好是用mutex;当用进程间互斥的时候,用sem。归结起来,mutex直接用到进程上,显得无用; sem用到线程上,显得画蛇添足。
1.1 信号量API
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
创建一个信号量,value值很重要,初始化信号量的为value。
int sem_unlink(const char *name);
依据名字来销毁信号量
sem_t *sem_open(const char *name, int oflag);
打开一个已经存在的信号量
int sem_close(sem_t *sem);
关闭一个信号量,并不是销毁它,依旧存在于内核中,只是从当前进程中卸载。
int sem_wait(sem_t *sem);
sem的值为0,就一直等待;否则就将sem的值-1
int sem_trywait(sem_t *sem);
sem的值为0,就放弃等待,返回值EAGAIN;否则就将sem的值-1
int sem_post(sem_t *sem);
sem的值+1
int sem_getvalue(sem_t *sem, int *
如果返回成功,sval就是sem当前值;否则就获取值出错了
1.2 信号量互斥锁的实现
信号量的互斥锁的类为SemMutex。
1.2.1 成员变量如下:
Sem mutex_; Sem实际上封装了一个sem*指针,初始化为SEM_FAILED
std::string name_; 信号量的名称
1.2.2 实现的成员函数如下:
SemMutex(const char* name);
构造函数初始化Mutex的名称
bool Create();
调用sem_open, 创建信号量, 重要的是信号量的计数初始化为1
bool Destroy();
销毁信号量
bool Open();
打开已经创建的信号量
bool IsOpen();
信号量是否已经打开,实际上判断sem指针是否为SEM_FAILED
bool Lock();
调用sem_wait, 如果信号量的值当前为0,一直等待,表示已经占用了锁资源; 否则sem的值就-1
bool UnLock();
调用sem_post, 释放锁资源,sem的值+1
bool TryLock();
调用sem_trywait, 如果锁资源已经占用,sem的值为0,就不用等待,直接返回EAGAIN。
int LockStatus();
获取锁的状态, -1 ,错误,0 - 加锁状态,1 - 无锁状态;实际上其调用sem_getvalue来获取sem的计数,来查看状态的。 实际上,实现互斥信号量,就是实现一个2值信号量,信号量的值一直在0和1之间变化;1 的时候是无锁状态,不会阻塞;0的时候是加锁状态,就会阻塞。
1.3 信号量读写锁的实现
信号量读写锁的实现,需要一个Sem来记录同时正在read的个数,以及一个SemMutex来实现互斥,其类为RWSem。
其关键就是锁状态的判定了。
p_mutex_->LockStatus == UNLOCK; 表明无锁
p_mutex_->LockStatus == LOCK && p_read_->GetValue() == 0; 已经加了写锁, 即已经加锁,但是读锁的个数为0
p_mutex_->LockStatus == LOCK && p_read_->GetValue() > 0; 已经加了读锁, 即已经加锁,但是读锁的个数>0
1.3.1 RWSem的成员变量:
SemMutex* p_mutex_; 实现读写互斥
Sem* p_read_; 记录当前正在读锁的个数
1.3.2 RWSem的成员函数:
bool Create();
创建p_mutex_和p_read_
bool Destroy();
销毁p_mutex_和p_read_
bool Open();
打开p_mutex_和p_read_
bool Close();
关闭p_mutex_和p_read_
bool WLock();
尝试读锁,当读锁已经占住了资源或者写锁站住资源,就会失败;而不管哪种锁占用了资源,p_mutex_的LockStatus都是锁住状态。 实现机制就是调用p_mutex_的Wait就OK了
bool TryWLock();
尝试读锁,当读锁已经占住了资源或者写锁站住资源,就会失败;而不管哪种锁占用了资源,p_mutex_的LockStatus都是锁住状态。 实现机制就是调用p_mutex_的TryWait就OK了
bool TryRLock();
当写锁占住资源的时候,返回false
当写锁没占住资源并且读锁也没占住资源的时候, p_read_调用Post,读锁的个数+1, 并且调用p_mutex_->Wait(),
当写锁没占住资源并且读锁已经占住资源的时候, p_read_调用Post, 读锁的个数+1, 不用调用p_mutex_->Wait(),否则会阻塞掉的。
bool RLock();
当写锁占住资源的时候,调用p_mutex_->Wait(), 让其阻塞
当写锁没占住资源并且读锁也没占住资源的时候, p_read_调用Post,读锁的个数+1, 并且调用p_mutex_->Wait(), 表示这个锁资源已经被占用
当写锁没占住资源并且读锁已经占住资源的时候, p_read_调用Post, 读锁的个数+1, 不用调用p_mutex_->Wait(),否则会阻塞掉的。
bool UnLock();
当加的锁为读锁的时候,调用p_read_.Post(), 读锁的个数-1,如果读锁的个数减到0,就调用p_mutex_->Post(), 解除锁资源的占用
当加的是写锁的时候, 调用p_mutex_.Post(),
int LockStatus();
0 - 无锁;1- 写锁;2-读锁