信号灯集是配合共享内存实现同步和互斥的机制。
1,创建信号灯集
semget();
2,初始化信号灯集的信号灯的值
semctl();
3;信号灯集的P操作
semop(int semid,sturct sembuf *opstr,size_t nops)
sturct sembuf *opstr为系统结构体
semid为信号灯集ID
struct sembuf{
short sem_num;
shirt sem_op: 0 等待
1 释放 V操作
-1 分配 P操作
short sem_flg 0 阻塞等待信号到来
IPC_NOWAIT 非阻塞不等待信号到来
SEM_LNDO 当前进程非法退出,把信号量的值还原到原先的状态
nops: 要操作的信号灯的个数
}
4,删除信号灯操作
int semctl(semid,int semnum IPC_RMID); //IPC_RMID从系统中删除信号灯集合
read和write两个进程通信使用信号灯集配合共享内存的机制
read.c代码如下
#include #include #include #include #include #include #include
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int init_sem_value(int sem_id,int num,int value)
{
union semun var;
var.val = value;
if(semctl(sem_id,num,SETVAL,var) < 0)
{
perror("Fail to semctl");
exit(EXIT_FAILURE);
}
return 0;
}
//P操作
void P(int sem_id,int num)
{
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = -1;
//SEM_UNDO :值的是进程异常退出的时候,释放它申请的资源
//IPC_NOWAIT:没有申请到资源的时候,不阻塞,立即返回
//0 :阻塞方式
buf.sem_flg = 0;
if(semop(sem_id,&buf,1) < 0)
{
perror("Fail to semop");
exit(EXIT_FAILURE);
}
return ;
}
//V操作
void V(int sem_id,int num)
{
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = 1;
//SEM_UNDO :值的是进程异常退出的时候,释放它申请的资源
//IPC_NOWAIT:没有申请到资源的时候,不阻塞,立即返回
//0 :阻塞方式
buf.sem_flg = 0;
if(semop(sem_id,&buf,1) < 0)
{
perror("Fail to semop");
exit(EXIT_FAILURE);
}
return ;
}
//./a.out .
int main(int argc, const char *argv[])
{
char *addr;
int shm_id;
key_t key;
//先运行
if((key = ftok(argv[1],'k')) < 0)
{
perror("Fail to key");
exit(EXIT_FAILURE);
}
printf("key = %#x.\n",key);
/*
*int shmget(key_t key, size_t size, int shmflg);
*第一个参数:
*1.IPC_PRIVATE,每次都会获得一个新的共享内存,主要用于有亲缘关系的进程
*2.通过ftok函数获得
* key_t key;
* key = ftok(pathname,字符);
*
*第二个参数:
*共享内存大小
*
*第三个参数:
*IPC_CREAT,IPC_EXCL,权限
*/
//如果对应的key的共享内存不存在,创建,然后返回其ID
//如果对应的key的共享内存存在,直接返回ID
if((shm_id = shmget(key,1024,IPC_CREAT | 0666)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE);
}
printf("shm_id = %d.\n",shm_id);
//映射共享内存
if( ( addr = (char *)shmat(shm_id,NULL,0) ) == (char *)-1 )
{
perror("Fail to shmat");
exit(EXIT_FAILURE);
}
//**************************信号灯集*******************
int sem_id;
//创建信号灯集
if((sem_id = semget(key,2,IPC_CREAT | IPC_EXCL | 0666) ) < 0)
{
if((sem_id = semget(key,2,IPC_CREAT | 0666)) < 0)
{
perror("Fail to semget");
exit(EXIT_FAILURE);
}
}else{
//初始化信号灯集信号灯的值
init_sem_value(sem_id,0,0);
init_sem_value(sem_id,1,1);
}
while(1)
{
P(sem_id,0);
printf("%s.\n",addr);
V(sem_id,1);
if(strncmp(addr,"quit",4) == 0)
break;
}
//解除映射
if(shmdt(addr) < 0)
{
perror("Fail to shmdt");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);;
}
write.c代码如下:
#include #include #include #include #include #include #include
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int init_sem_value(int sem_id,int num,int value)
{
union semun var;
var.val = value;
if(semctl(sem_id,num,SETVAL,var) < 0)
{
perror("Fail to semctl");
exit(EXIT_FAILURE);
}
return 0;
}
//P操作
void P(int sem_id,int num)
{
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = -1;
//SEM_UNDO :值的是进程异常退出的时候,释放它申请的资源
//IPC_NOWAIT:没有申请到资源的时候,不阻塞,立即返回
//0 :阻塞方式
buf.sem_flg = 0;
if(semop(sem_id,&buf,1) < 0)
{
perror("Fail to semop");
exit(EXIT_FAILURE);
}
return ;
}
//V操作
void V(int sem_id,int num)
{
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = 1;
//SEM_UNDO :值的是进程异常退出的时候,释放它申请的资源
//IPC_NOWAIT:没有申请到资源的时候,不阻塞,立即返回
//0 :阻塞方式
buf.sem_flg = 0;
if(semop(sem_id,&buf,1) < 0)
{
perror("Fail to semop");
exit(EXIT_FAILURE);
}
return ;
}
//./a.out .
int main(int argc, const char *argv[])
{
char *addr;
int shm_id;
key_t key;
//先运行
if((key = ftok(argv[1],'k')) < 0)
{
perror("Fail to key");
exit(EXIT_FAILURE);
}
printf("key = %#x.\n",key);
/*
*int shmget(key_t key, size_t size, int shmflg);
*第一个参数:
*1.IPC_PRIVATE,每次都会获得一个新的共享内存,主要用于有亲缘关系的进程
*2.通过ftok函数获得
* key_t key;
* key = ftok(pathname,字符);
*
*第二个参数:
*共享内存大小
*
*第三个参数:
*IPC_CREAT,IPC_EXCL,权限
*/
//如果对应的key的共享内存不存在,创建,然后返回其ID
//如果对应的key的共享内存存在,直接返回ID
if((shm_id = shmget(key,1024,IPC_CREAT | 0666)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE);
}
printf("shm_id = %d.\n",shm_id);
//映射共享内存
if( ( addr = (char *)shmat(shm_id,NULL,0) ) == (char *)-1 )
{
perror("Fail to shmat");
exit(EXIT_FAILURE);
}
//**************************信号灯集*******************
int sem_id;
//创建信号灯集
if((sem_id = semget(key,2,IPC_CREAT | IPC_EXCL | 0666) ) < 0)
{
if((sem_id = semget(key,2,IPC_CREAT | 0666)) < 0)
{
perror("Fail to semget");
exit(EXIT_FAILURE);
}
}else{
//初始化信号灯集信号灯的值
init_sem_value(sem_id,0,0);
init_sem_value(sem_id,1,1);
}
while(1)
{
P(sem_id,1);
fgets(addr,1024,stdin);
V(sem_id,0);
if(strncmp(addr,"quit",4) == 0)
break;
}
//解除映射
if(shmdt(addr) < 0)
{
perror("Fail to shmdt");
exit(EXIT_FAILURE);
}
//删除共享内存对象
//真正删除:在共享内存映射次数为0的时候,才会删除
if(shmctl(shm_id,IPC_RMID,NULL) < 0)
{
perror("Fail to shmctl");
exit(EXIT_FAILURE);
}
usleep(500);
//删除信号灯集合
if(semctl(sem_id,0,IPC_RMID) < 0)
{
perror("Fail to semctl");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);;
}