利用POSIX互斥锁和条件变量实现的信号量

时间:2022-12-13 15:14:39

在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版本。

参考

Linux下利用条件变量实现信号量机制

《利用POSIX互斥锁和条件变量实现的信号量》