有名信号量 semphore


如果说信号是外部事件和进程的关联的机制的话,那么信号量就是进程、线程之间通信的机制。根据是支持不同进程之间的通信还是同一个进程内不同线程的通信,信号量可以分为有名信号量和无名信号量。顾名思义,有名信号量在建立起来时需要显式地指名一个信号量的名字,在linux这个名字对应到/dev/shm-semphorename这个共享内存的映射文件,由于它可以被不同进程同时访问,因而可以在不同进程之间实现通信;而无名信号仅仅用在同一个进程内部的不同线程之间,由于不同线程共享创建它们的进程的资源,因而无需显示地指定任何可以共同访问的名称或文件。两者的共同点是都支持经典的P/V操作,在申请信号量的时候,如果申请不到可以被调度到休眠状态,直至被V操作唤醒。


下面基于CentOS Linux系统分别进行介绍有名信号量和无名信号量。


有名信号量


依赖头文件

#include <fcntl.h>           /* For O_* constants */

#include <sys/stat.h>        /* For mode constants */

#include <semaphore.h>


常用函数


创建有名信号量

sem_t *sem_open(const char *name, int oflag);

sem_t *sem_open(const char *name, int oflag,  mode_t mode, unsigned int value);


P操作

int sem_wait(sem_t *sem); //如果信号量不大于0,则当前线程或进程一直阻塞到信号量大于0


int sem_trywait(sem_t *sem);//如果信号量不大于0,返回出错值并不会阻塞当前线程或进程


int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);//如果信号量不大于0,当前线程或进程会被阻塞abs_timeout指定的时间,然后继续进入运行队列



V操作

int sem_post(sem_t *sem);


关闭信号

int sem_close(sem_t *sem); //使得系统允许任何为这个信号量申请的任何资源可以被释放

int sem_unlink(sem_t *sem);//删除sem指向的有名信号量


查询当前信号量的值

int sem_getvalue(sem_t *sem, int *sval);//把当前信号量的值读取到sval当中去。



连接依赖库

依赖于线程库,在链接的时候需要加上-lpthread。


代码实例:sem_svc.c

#include <stdio.h>

#include <stdint.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

#include <fcntl.h>           /* For O_* constants */

#include <sys/stat.h>        /* For mode constants */

#include <semaphore.h>


const char * fname = "tstmy";

void main(void)

{

pthread_t ftids;


sem_t * svc_sem;


svc_sem = sem_open(fname, O_CREAT | O_EXCL, 0644, 0);


printf("Will post semp soon ...\n");

sleep(2);

sem_post(svc_sem);


printf("Will post semp again ...\n");

sleep(2);

sem_post(svc_sem);


printf("Post semp done!\n");


sem_close(svc_sem);

sem_unlink(fname);

}


sem_clnt.c:

#include <stdio.h>

#include <stdint.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


#include <fcntl.h>           /* For O_* constants */

#include <sys/stat.h>        /* For mode constants */

#include <semaphore.h>

const char * fname = "tstmy";


sem_t * clnt_sem;


void state_thread()

{

while(1) {

printf("Wait semp....\n");

sem_wait(clnt_sem);

printf("Wait semp done: semp comes\n");

}

}  


void main(void)

{

pthread_t ftids;


clnt_sem = sem_open(fname,O_EXCL);


pthread_create(&ftids, NULL, (void *)state_thread, NULL);


while(1) {

printf("IN Clnt main process\n");

sleep(1);

}

}


编译链接如下:

[xmch@localhost testcases]$ gcc -o sem_svc sem_svc.c -lpthread

[xmch@localhost testcases]$ gcc -o sem_clnt sem_clnt.c -lpthread



典型应用场景:

1.基于它实现多个进程之间的读写锁/或者生产者消费者模型;

2.需要实现属于不同进程的多个线程之间的通信同步关系;


注意:上面实例代码sem_svc.c中的sem_close()和sem_unlink不能忽略掉,否则下次运行执行到sem_open()时候会出错,务必引起重视,特别地在多线程、进程的环境下,这两个函数建议放在系统或者模块的清理函数(de-init或者destruct)中去执行。