上海网站设计软件,网络工程技术主要学什么,厦门最新通告,手机开发者选项是干嘛用的4 信号量
信号量是专门用来解决进程同步与互斥问题的一种通信机制#xff0c;它与信号无关#xff1b;不同于管道、FIFO以及消息队列#xff0c;一般不用来传输数据#xff1b;信号量包括#xff1a;表示资源数量的非负整型变量、修改信号量的原子操作P和V、该信号量下等…4 信号量
信号量是专门用来解决进程同步与互斥问题的一种通信机制它与信号无关不同于管道、FIFO以及消息队列一般不用来传输数据信号量包括表示资源数量的非负整型变量、修改信号量的原子操作P和V、该信号量下等待资源的进程队列。
使用信号量进行通信时通常需要如下步骤
创建信号量/信号量集或者获取系统中已有的信号量/信号量集初始化信号量早期信号量通常初始化为1但有些进程一次需要多个同类的临界资源或多个不同类且唯一的临界资源因此可能需要初始化信号量集信号量的P、V操作根据进程请求修改信号量的数量P操作使信号量-1V操作使信号量1从系统中删除不需要的信号量。
Linux内核提供了三个系统调用
semgetsemctlsemop
4.1 semget函数
#include sys/sem.hint semget(key_t key, int nsems, int semflg);功能创建一个新的信号量集或获取一个已经存在的信号量集。
参数说明
key传入参数信号量的键值通常为一个整数nsems创建的信号量数目semflg标志位同open和msgget函数的标志位功能相似用来设置权限 – 权限位可与IPC_CREAT及IPC_EXCL发生位或 – IPC_PRIVATE表示该信号量为当前进程的私有信号量。
返回值说明
成功返回信号量的标识符不成功返回-1并设置errno常见errno值如下 – EACCES表示进程无访问权限 – ENOENT表示传入的键值不存在 – EINVAL表示nsems小于0或信号量已达上限 – EEXIST当semflg设置为IPC_CREAT和IPC_EXCL时该信号量已存在。
4.2 semctl函数
#include sys/sem.hint semctl(int semid, int semnum, int cmd, ...);功能对信号量或信号量集进行控制。
参数说明
semid信号量标识符通常为semget函数的返回值semnum信号量在信号量集中的编号该参数在使用信号量集时才会使用通常设置为0表示取第一个信号cmd对信号量进行操作常用的设置为SETVAL和IPC_RMID – SETVAL表示semctl函数的功能为初始化信号量的值信号量的值通过可选参数传入信号量在使用前应先对其值进行设置 – IPC_RMID表示semctl函数的功能为删除指定信号量。信号量的删除应由其所有者或创建者进行没有被删除的信号量将会一直存在于系统中。最后一个参数是可选参数依赖于参数cmd使用该参数时用户必须在程序自定义一个如下所示的共用体
union semun{int val; //cmd SETVAL, 用于指定信号量值struct semid_ds *buf; //cmd IPC_STAT或IPC_SET, 该项才生效unsigned short *array; //cmd GETALL或SETALL, 该项才生效struct seminfo *_buf; //cmd IPC_INFO, 该项才生效
};
//semid_ds是一个由内核维护的记录信号量属性信息的结构体
struct semid_ds{struct ipc_perm sem_perm; //所有者和标识权限time_t sem_otime; //最后操作时间time_t sem_ctime; //最后更改时间unsigned short sem_nsems; //信号集中的信号数量
};返回值说明
成功根据参数cmd的取值返回相应信息通常为一个非负整数不成功返回-1并设置errno。
4.3 semop函数
#include sys/sem.hint semop(int semid, struct sembuf *sops, unsigned nsops);功能改变信号量的值。
参数说明
semid信号量标识符通常为semget函数的返回值sops一个struct sembuf类型的数组指针该数组中的每个元素设置了要对信号量集的哪个信号做哪种操作
struct sembuf{short sem_num; //信号量在信号量集中的编号short sem_op; //信号量操作short sem_flag; //标志位
};– sem_op -1表示P操作 – sem_op 1表示V操作 – 通常设置sem_flag SEM_UNDO若进程退出前没有删除信号量则信号量将会由系统自动释放。
nsops表示参数sops所指数组中元素的个数。
返回值说明
成功返回0不成功返回-1并设置errno。
【案例1】使用信号量实现父子进程同步防止父子进程抢夺CPU。
#include stdio.h
#include stdlib.h
#include sys/sem.h
//自定义共用体
union semu{int val;struct semid_ds* buf;unsigned short* array;struct seminfo* _buf;
};
static int semId;
//设置信号量值
static int setSemValue() {union semu tempSemUnion;tempSemUnion.val 1;if (semctl(semId, 0, SETVAL, tempSemUnion) -1){return 0;}//of ifreturn 1;
}//of setSemValue
//p操作获取信号量
static int semaphoreP() {struct sembuf tempSemBuf;tempSemBuf.sem_num 0;tempSemBuf.sem_op -1;tempSemBuf.sem_flg SEM_UNDO;if (semop(semId, tempSemBuf, 1) -1){perror(sem_p err);return 0;}//of ifreturn 1;
}//of semaphoreP
//V操作释放信号量
static int semaphoreV() {struct sembuf tempSemBuf;tempSemBuf.sem_num 0;tempSemBuf.sem_op 1;tempSemBuf.sem_flg SEM_UNDO;if (semop(semId, tempSemBuf, 1) -1){perror(sem_v err);return 0;}//of ifreturn 1;
}//of semaphoreV
//删除信号量
static void delSemValue() {union semu tempSemUnion;if (semctl(semId, 0, IPC_RMID, tempSemUnion) -1){perror(del err);}//of if
}//of delSemValue
int main() {int i;pid_t temPid;char tempChar C;semId semget((key_t)1000, 1, 0664 | IPC_CREAT);//创建信号量if (semId -1){perror(sem_c err);exit(-1);}//of ifif (!setSemValue()){ //设置信号量值perror(init err);exit(-1);}//of iftemPid fork(); //创建子进程if (temPid -1){ //若创建失败delSemValue(); //删除信号量exit(-1);} else if (temPid 0){ //设置子进程打印的字符tempChar Z;} else { //设置父进程打印的字符tempChar C;}//of ifsrand((unsigned int)getpid()); //设置随机数种子for (i 0; i 8; i) { //循环打印字符semaphoreP(); //获取信号量printf(%c, tempChar);fflush(stdout); //将字符打印到屏幕sleep(rand() % 4); //沉睡printf(%c, tempChar);fflush(stdout); //再次打印到屏幕sleep(1);semaphoreV(); //释放信号量}//of for iif (temPid 0){wait(NULL); //回收子进程delSemValue(); //删除信号量}//of ifprintf(\nprocess %d finished.\n, getpid());return 0;
}//of main