有名信号量 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)中去执行。