量在此過程中負責數據操作的互斥、同步等功能。
當請求一個使用信號量來表示的資源時,進程需要先讀取信號量的值來判斷資源是否可用。大于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操作均正確,說明互斥鎖加上了
這就是為什么要給進程加上信號量
新聞熱點
疑難解答