只用于多进程间的并发控制
一个信息量集合(信号量集 或 信息量数组)中顺序存储着多个信号量
相关接口函数:
实际项目,直接调用semop函数来作为某个或某几个信号量的PV操作函数会很不方便,因此会对信号量集合的接口进行二次封装,封装方案:
1. 项目中用到几个信号量就创建几个信号量集合,每个信号量集合中仅包含一个信号量,然后基于每个信号量集合封装相应的初始化、P、V操作函数
**2.**项目中创建一个信号量集合,该集合包含所有需要的信号量,然后针对每个信号量封装它的初始化、P、V操作函数
一般建议项目中使用的信号量比较少时用第1方案,否则使用第2方案
以下采用第2方案:
cpp
#define SEM_NUM ?
union semun
{
int val;
unsigned short *pval;
};
// create_and_init_sem_set() 创建并初始化
int create_and_init_sem_set(const char *pathname,int no,unsigned short *pallval,int semnum);
// sem_p_by_index() p操作
int sem_p_by_index(int semid,int index,int shrnum);
// sem_v_by_index() v操作
int sem_v_by_index(int semid,int index,int shrnum);
/*针对集合中下标为0的信号量编写PV操作带参宏*/
#define sem_0_p(semid,shrnum) sem_p_by_index(semid,0,shrnum)
#define sem_0_v(semid,shrnum) sem_v_by_index(semid,0,shrnum)
/*针对集合中下标为1的信号量编写PV操作带参宏*/
#define sem_1_p(semid,shrnum) sem_p_by_index(semid,1,shrnum)
#define sem_1_v(semid,shrnum) sem_v_by_index(semid,1,shrnum)
。。。。。。
/*针对集合中下标为x的信号量编写PV操作带参宏*/
#define sem_x_p(semid,shrnum) sem_p_by_index(semid,x,shrnum)
#define sem_x_v(semid,shrnum) sem_v_by_index(semid,x,shrnum)
示例代码:
my_semset.h
cpp
#ifndef MY_SEMSET_H
#define MY_SEMSET_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MY_SEM_NUM 1
union semun{ // 信号量集合
int val;
unsigned short *pvals;
};
// create_and_init_sem_set() 创建并初始化
int create_and_init_semset(const char *pathname,int no,unsigned short *pallval,int valnum);
// sem_p_by_index() p操作
int sem_p_by_index(int semid,int index,int shrnum);
// sem_v_by_index() v操作
int sem_v_by_index(int semid,int index,int shrnum);
#define sem_0_p(semid,shrnum) sem_p_by_index(semid,0,shrnum)
#define sem_0_v(semid,shrnum) sem_v_by_index(semid,0,shrnum)
#if 0
#define sem_1_p(semid,shrnum) sem_p_by_index(semid,1,shrnum)
#define sem_1_v(semid,shrnum) sem_v_by_index(semid,1,shrnum)
#define sem_2_p(semid,shrnum) sem_p_by_index(semid,2,shrnum)
#define sem_2_v(semid,shrnum) sem_v_by_index(semid,2,shrnum)
#endif
#endif
my_semset.c
cpp
#include "my_semset.h"
int create_and_init_semset(const char *pathname,int no,unsigned short *pallval,int valnum){
key_t key;
int semid = -1;
union semun un;
if(valnum < MY_SEM_NUM){
printf("The valnum is too small\n");
return -1;
}
key = ftok(pathname,no); // ftok() 获取key值
semid = semget(key,MY_SEM_NUM,IPC_CREAT | IPC_EXCL | 0666); // semget() 获取id
if(semid < 0){ // semset is exist 已经存在就不用初始化了直接获取
semid = semget(key,MY_SEM_NUM,IPC_CREAT | 0666);
}
else{ // semset is not exist 不存在需要先创建再调用semctl()初始化
un.pvals = pallval;
semctl(semid,0,SETALL,un); // semctl()设置初值
}
return semid;
}
int sem_p_by_index(int semid,int index,int shrnum){
struct sembuf op;
if(shrnum <= 0){
printf("shrnum = %d is invalid\n",shrnum);
return -1;
}
op.sem_num = index;
op.sem_op = -shrnum;
op.sem_flg = SEM_UNDO;
return semop(semid,&op,1);
}
int sem_v_by_index(int semid,int index,int shrnum){
struct sembuf op;
if(shrnum <= 0){
printf("shrnum = %d is invalid\n",shrnum);
return -1;
}
op.sem_num = index;
op.sem_op = shrnum;
op.sem_flg = 0;
return semop(semid,&op,1);
}
input.c
cpp
#include "../../semset/my_semset.h"
#include <sys/ipc.h>
#include <sys/shm.h>
char *input_string(char *buf,int size);
int main(int argc, char *argv[]){
unsigned short val = 0;
int semid = create_and_init_semset("./input.c",8,&val,1);
key_t shmkey;
int shmid = -1;
char *pshm = NULL;
shmkey = ftok("./input.c",88); // 获取input.c的key值
shmid = shmget(shmkey,40,IPC_CREAT | 0666); // shmget() 创建并打开一个共享内存,获取id
pshm = shmat(shmid,NULL,0); // shmat() 获取指定内存块的首地址
while(1){
printf("Please input a string:\n");
input_string(pshm,40); // 读到共享内存中
sem_0_v(semid,1); // v操作
if(strcmp(pshm,"byebye") == 0) break; // 出口
}
shmdt(pshm); //shmdt()
pshm = NULL;
return 0;
}
output.c
cpp
#include "../../semset/my_semset.h"
#include <sys/ipc.h>
#include <sys/shm.h>
char *input_string(char *buf,int size);
int main(int argc, char *argv[]){
unsigned short val = 0;
int semid = create_and_init_semset("./input.c",8,&val,1); // create_and_innit()
key_t shmkey;
int shmid = -1;
char *pshm = NULL;
shmkey = ftok("./input.c",88); // ftok()
shmid = shmget(shmkey,40,IPC_CREAT | 0666); // shmget() 创建并打开一个共享内存
pshm = shmat(shmid,NULL,0); // shmat() 获取指定内存块的首地址
while(1){
sem_0_p(semid,1); // p操作
if(strcmp(pshm,"byebye") == 0) break; // 出口
else printf("the input string is %s\n",pshm);
}
shmdt(pshm); // shmdt()
pshm = NULL;
return 0;
}
input_string.c ( 读取 size 个数据存到 buf 里返回**)**
cpp
#include <stdio.h>
#include <string.h>
char *input_string(char *buf,int size){
int len = 0;
fgets(buf,size,stdin);
len = strlen(buf);
if(*(buf + len - 1) == '\n') *(buf + len - 1) = '\0';
else while(getchar() != '\n'){}
return buf;
}