量在此过程中负责数据操作的互斥、同步等功能。
当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用。当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性。信号量的值得+1-1操作即为PV操作
为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任何时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程对共享资源的访问的。其中共享内存的使用就要用到信号量
下面是在linux下的信号量实现代码
sem.h
#ifndef _SEM_#define _SEM_#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/sem.h>#include<sys/ipc.h>#include<string.h>#include<errno.h>#define KEY_PATH "."#define PROJID 88int creatSem(int semsetNum);int initSem(int semId,int which);int P(int semId,int which);int V(int semId,int which);int destorySem(int semId);int showSemVal(int semId,int semNum);int getSem();union semun_t{ int val; struct semid_ds*buf; unsigned short*array; struct seminfo* _buf;}semun;#endifsem.c#include"sem.h"int creatSem(int semsetNum){int creatflag=IPC_CREAT|IPC_EXCL;key_t k=ftok(KEY_PATH,PROJID);return semget(k,semsetNum,creatflag);}static int op_sem(int semId,int op,int which){ struct sembuf sem; memset(&sem,'/0',sizeof(sem)); sem.sem_num=which; sem.sem_op=op; sem.sem_flg=0; return semop(semId,&sem,1);}int initSem(int semId,int which){//semun_t semun;semun.val=1;int ret=semctl(semId,which,SETVAL,semun);if(ret==-1){ return ret;}return ret;}int P(int semId,int which){int ret=op_sem(semId,-1,which);if(ret==0){ printf("P Operate is sucess! errno code is: %d/n",errno);}else{printf("P operate is fail! errno code is:%d/n",errno);}return ret;}int V(int semId,int which){int ret=op_sem(semId,1,which);if(ret==0){ printf("V operate is sucess! errno code is: %d/n",errno);}else{ printf("V operate is sucess! errno code is: %d/n",errno);}return ret;}int destorySem(int semId){int ret=semctl(semId,0,IPC_RMID,NULL);if(ret==-1){ printf("destory sem error/n"); return ret;}return ret;}int showSemVal(int semId,int semNum){//semun_t semun;unsigned short* semlist=(unsigned short*)malloc(sizeof(unsigned short)* semNum);if(semlist==NULL){ printf("malloc error,error code is :%d/n",errno); return 1;}memset(semlist,'/0',sizeof(unsigned short)*semNum);semun.array=semlist;int ret=semctl(semId,0,GETALL,semun);if(ret==-1){ printf("get sem error:error code is: %d/n",errno);}else{ int i=0; for(i;i<semNum;i++){ printf("sem[%d]is:%d/n",i,semun.array[i]); }}free(semlist);semun.array=NULL;return ret;}int getSem(){key_t k=ftok(KEY_PATH,PROJID);return semget(k,0,0);}测试代码#include<sys/wait.h>#include"sem.h"int main(){ int semid=creatSem(1);// printf("semid is :%d/n",semid); initSem(semid,0); pid_t id =fork(); if(id==0) { printf("child runing..,pid:%d ppid:%d/n",getpid(),getppid()); while(1) { printf("A"); usleep(100000); fflush(stdout); printf("A"); usleep(200000); fflush(stdout); } } else{ printf("father runing..,pid:%d ppid:%d/n",getpid(),getppid()); while(1) { printf("B"); usleep(300000); fflush(stdout); printf("B"); usleep(400000); fflush(stdout); } wait(NULL); } P(semid,0); sleep(5); V(semid,0); destorySem(semid); return 0;}Makefile.PHONY:allall:testtest: sem.c test.c gcc -o $@ $^.PHONY:cleanclean: rm -f sem test测试结果
发现即出现了单数的A也出现了单数的B,这说明两个线程同时进行工作,下面用信号量给父子进程都加上互斥锁
测试代码
#include<sys/wait.h>#include"sem.h"int main(){ int semid=creatSem(1);// printf("semid is :%d/n",semid); initSem(semid,0); pid_t id =fork(); if(id==0) { // printf("child runing..,pid:%d ppid:%d/n",getpid(),getppid()); while(1) { P(semid,0); printf("A"); usleep(100000); fflush(stdout); printf("A"); usleep(200000); fflush(stdout); V(semid,0); } } else{ // printf("father runing..,pid:%d ppid:%d/n",getpid(),getppid()); while(1) { P(semid,0); printf("B"); usleep(300000); fflush(stdout); printf("B"); usleep(400000); fflush(stdout); V(semid,0); } wait(NULL); } // P(semid,0); // sleep(5);// V(semid,0); destorySem(semid); return 0;}测试结果
![]()
AB都是成对出现,且PV操作均正确,说明互斥锁加上了
这就是为什么要给进程加上信号量
新闻热点
疑难解答