利用POSIX互斥锁和条件变量实现的信号量
在LwIP移植的代码中有信号量相关接口,但是是通过线程来模拟的。
以前读过,最近才感觉它是在 利用POSIX互斥锁和条件变量实现POSIX的信号量。
在《Unix网络编程 卷二进程间通信》中有用System V模拟 POSIX信号量的论述。
LwIP是一个轻型TCP/IP协议栈,它利用操作系统模拟层实现了信号灯。
主要有如下接口函数:
/**新建一个信号灯,并初始化灯的值为count*/
sys_sem_t sys_sem_new(u8_t count);
/**将标示符为sem的信号灯释放掉。*/
void sys_sem_free(sys_sem_t sem);
/**将标示符为sem的信号灯的值加1*/
void sys_sem_signal(sys_sem_t sem);
/**锁住——等待*/
u32_t sys_sem_wait(struct sys_sem **s);
sys_sem结构
struct sys_sem {
unsigned int c;
pthread_cond_t cond;
pthread_mutex_t mutex;
};
typedef sys_sem * sys_sem_t;
初始化与释放直接调用了malloc/free这对好基友。
sys_sem_t sys_sem_new(u8_t count)
{
sys_sem_t sem = (sys_sem_t) malloc(sizeof(sys_sem));
if(sem)
{
sem->c = count;
pthread_cond_init(&(sem->cond), NULL);
pthread_mutex_init(&(sem->mutex), NULL);
return sem;
}
return NULL;
}
void sys_sem_free(sys_sem_t sem)
{
pthread_cond_destroy(&(sem->cond));
pthread_mutex_destroy(&(sem->mutex));
free(sem);
}
重点是PV操作,分别对应sys_sem_wait 和 sys_sem_signal
u32_t sys_sem_wait(struct sys_sem **s)
{
struct sys_sem *sem;
sem = *s;
pthread_mutex_lock(&(sem->mutex));
//进入的数目有限
while (sem->c <= 0) {
pthread_cond_wait(&(sem->cond), &(sem->mutex));
}
sem->c--;//消费了一个
pthread_mutex_unlock(&(sem->mutex));
}
void sys_sem_signal(struct sys_sem **s)
{
struct sys_sem *sem;
sem = *s;
pthread_mutex_lock(&(sem->mutex));
sem->c++;
//设计的只是二值选项?
if (sem->c > 1) {
sem->c = 1;
}
pthread_cond_broadcast(&(sem->cond));
pthread_mutex_unlock(&(sem->mutex));
}
但LwIP的V实现,感觉有些不对,其将sem实现为二值的了,由于sys_sem主要提供给sys_mbox(参考定义如下)。
/*移植信号量代码*/
struct sys_mbox {
int first, last;
void *msgs[SYS_MBOX_SIZE];
struct sys_sem *not_empty;
struct sys_sem *not_full;
struct sys_sem *mutex;
int wait_send;
};
由于not_empty、not_full和mutex都是二值,所以不影响使用,但是个人结合《Linux下利用条件变量实现信号量机制 》还是以为V的实现中if是不用的。
相应修改为
void sys_sem_signal(struct sys_sem **s)
{
struct sys_sem *sem;
sem = *s;
pthread_mutex_lock(&(sem->mutex));
++(sem->c);
if(sem->c > 0)
pthread_cond_broadcast(&(sem->cond));
pthread_mutex_unlock(&(sem->mutex));
}
u32_t sys_sem_wait(struct sys_sem **s)
{
struct sys_sem *sem;
sem = *s;
pthread_mutex_lock(&(sem->mutex));
//进入的数目有限
while (sem->c <= 0) {
pthread_cond_wait(&(sem->cond), &(sem->mutex));
}
--(sem->c);//消费了一个
pthread_mutex_unlock(&(sem->mutex));
}
以上代码可以看做是《Linux下利用条件变量实现信号量机制 》的C版本。
参考