1.什么是信号量
信号量是一种特殊的变量,访问具有原子性。
只允许对它进行两个操作:
1)等待信号量
当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行。
2)发送信号量
将信号量值加1。
我们使用信号量,来解决进程或线程间共享资源引发的同步问题。
2.Linux中信号量的使用
Linux提供了一组信号量API,声明在头文件sys/sem.h中。
1)semget函数:新建信号量
int semget(key_t key,int num_sems,int sem_flags);
key:信号量键值,可以理解为信号量的唯一性标记。
num_sems:信号量的数目,一般为1
sem_flags:有两个值,IPC_CREATE和IPC_EXCL,
IPC_CREATE表示若信号量已存在,返回该信号量标识符。
IPC_EXCL表示若信号量已存在,返回错误。
返回值:相应的信号量标识符,失败返回-1
2)semop函数:修改信号量的值
int semop(int sem_id,struct sembuf *sem_opa,size_t num_sem_ops);
sem_id:信号量标识符
sem_opa:结构如下
struct sembuf{
short sem_num;//除非使用一组信号量,否则它为0
short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
//一个是+1,即V(发送信号)操作。
short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,
//并在进程没有释放该信号量而终止时,操作系统释放信号量
};
3)semctl函数:用于信号量的初始化和删除
int semctl(int sem_id,int sem_num,int command,[union semun sem_union]);
command:有两个值SETVAL,IPC_RMID,分别表示初始化和删除信号量。
sem_union:可选参数,结构如下:
union semun{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
一般用到的是val,表示要传给信号量的初始值。
3.Linux信号量使用示例
下例中,我们写了一个程序,程序中有一个char类型的字符,char message='x'
然后同时运行这个程序的两个实例。
第一个实例,带一个参数,将参数的第一个字符赋给message,比如为'0'
第二个实例,使用默认message值'x'
我们的目的是,使用信号量,循环执行这两个实例,
我们可以看到执行结果应该是'x0x0x0x0x0x0'
#include<stdio.h>
#include<stdlib.h>
#include<sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int sem_id;
int set_semvalue()
{
union semun sem_union;
sem_union.val = ;
if(semctl(sem_id,,SETVAL,sem_union)==-)
return ;
return ;
}
int semaphore_p()
{
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = -;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,)==-)
{
fprintf(stderr,"semaphore_p failed\n");
return ;
}
return ;
}
int semaphore_v()
{
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = ;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,)==-)
{
fprintf(stderr,"semaphore_v failed\n");
return ;
}
return ;
}
void del_semvalue()
{
//删除信号量
union semun sem_union;
if(semctl(sem_id,,IPC_RMID,sem_union)==-)
fprintf(stderr,"Failed to delete semaphore\n");
}
int main(int argc,char *argv[])
{
char message = 'x';
//创建信号量
sem_id = semget((key_t),,|IPC_CREAT);
if(argc>)
{
//初始化信号量
if(!set_semvalue())
{
fprintf(stderr,"init failed\n");
exit(EXIT_FAILURE);
}
//参数的第一个字符赋给message
message = argv[][];
}
int i=;
for(i=;i<;i++)
{
//等待信号量
if(!semaphore_p())
exit(EXIT_FAILURE);
printf("%c",message);
fflush(stdout);
sleep();
//发送信号量
if(!semaphore_v())
exit(EXIT_FAILURE);
sleep();
}
printf("\n%d-finished\n",getpid());
if(argc>)
{
//退出前删除信号量
del_semvalue();
}
exit(EXIT_SUCCESS);
}
输出结果: