目录
4.3信号量集
4.3.1 概念和原理
(不是用于进程间传递数据、而是用于进程间访问控制)
信号量集是一个信号量的集合,可以存放多个信号量
而信号量就是一个计数器, 用于记录进程的访问次数, 每来一个进程访问计数值-1(P操作),每离开一个进程计数值+1(V操作)
当计数值为0时就不在允许进程访问,直到计数值重新大于0为止才能允许
那什么时候用到这个呢?
之前在共享内存后面我提到一个问题
如果对于同一个资源, 一个进程对它写, 同时另一个进程又对它读
这会乱 !!!
因此才需要进程的互斥和同步解决上述遇到的问题
而进程的互斥和同步就是用到了信号量集
下面来看下它如何使用吧
4.3.2 使用
1)ftok获取key
2)通过key创建/获取信号量集 ------- semget
参数:
key - 上一步获取的key
nsems - 信号量集中信号量的个数(信号量集的长度)
semflg - 创建标志和权限
IPC_CREAT|0666
3)如果是创建需要设置信号量集中信号量的初始计数 ----- semctl
semctl(信号量集ID,信号量在信号量集中的下标,SETVAL,初始计数值);
4)对信号量进行P-V操作 ------ semop
参数:
semid - 信号量集的ID
sops - 信号量操作数组首地址
nsops - 信号量操作数组的元素个数
成功返回0,失败返回-1
struct sembuf结构体中包含以下成员:
unsigned short sem_num; /* 信号量的下标 */
short sem_op; /* 操作方式 -1 / 1 */
short sem_flg; /* 等待方式: 0:阻塞方式 IPC_NOWAIT:非阻塞方式*/
5)不再使用可以删除 -------- semctl
进程1创建共享内存, 因为要和进程2访问同一个资源所以再创建一个信号量集,进程1的代码如下:(进程的互斥)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>
void *p = NULL;
int shmid,semid;
void func(int sig)
{
shmdt(p);
shmctl(shmid,IPC_RMID,0);
exit(0);
}
int main()
{
char buf[100] = {};
signal(SIGINT,func);
//1.获取key
key_t key = ftok(".",'x');
if(key==-1){
perror("ftok");
exit(-1);
}
//2.创建共享内存
shmid = shmget(key,100,IPC_CREAT|0666);
if(shmid==-1){
perror("shmget");
exit(-1);
}
//3.映射共享内存
p = shmat(shmid,0,0);
if(p==(void *)-1){
perror("shmat");
exit(-1);
}
//4.创建信号量集
semid = semget(key,1,IPC_CREAT|0666);
if(semid==-1){
perror("semget");
exit(-1);
}
//5.设置信号量初始值1
int res = semctl(semid,0,SETVAL,1);
if(res==-1){
perror("semctl");
exit(-1);
}
while(1){
//P操作, 信号量-1
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid,&sem,1);
//写共享内存,发送
printf("请输入:");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
strcpy((char *)p,buf);
//V操作,信号量+1
sem.sem_op = 1;
semop(semid,&sem,1);
}
return 0;
}
进程2的代码如下:(进程的互斥)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>
void *p = NULL;
int shmid,semid;
void func(int sig)
{
shmdt(p);
semctl(semid,0,IPC_RMID);
exit(0);
}
int main()
{
signal(SIGINT,func);
//1.获取key
key_t key = ftok(".",'x');
if(key==-1){
perror("ftok");
exit(-1);
}
//2.共享内存
shmid = shmget(key,0,0);
if(shmid==-1){
perror("shmget");
exit(-1);
}
//3.映射共享内存
p = shmat(shmid,0,0);
if(p==(void *)-1){
perror("shmat");
exit(-1);
}
//4.信号量集
semid = semget(key,0,0);
if(semid==-1){
perror("semget");
exit(-1);
}
while(1){
//P操作, 信号量-1
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid,&sem,1);
printf("%s\n",(char *)p);
//V操作,信号量+1
sem.sem_op = 1;
semop(semid,&sem,1);
}
return 0;
}