[Linux]信号量
生活随笔
收集整理的這篇文章主要介紹了
[Linux]信号量
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
信號量是一個計數器,用于為多個進程提供對共享數據對象的訪問。
在信號量上只有三種操作可以進行,初始化、遞增和增加,這三種操作都是原子操作。遞減操作可以用于阻塞一個進程,增加操作用于解除阻塞一個進程。
為了獲得共享資源,需要測試信號量,若信號量為正,則進程可以使用該資源,這時信號量值減一。否則信號量值為0,進程進入休眠狀態。當進程不再使用由一個信號量控制的共享資源時,信號量值加一。如果有正在休眠的進程,則喚醒它們。常用的信號量的形式為二元信號量。即是原子性的。
信號量的功能:負責數據操作的互斥、同步等功能。本質上是一種數據操作鎖。
我們為什么要使用信號量呢?為了防止出現因多個程序同時訪問一個共享資源而引發的一系列問題,我們需要一種方法,它可以通過生成并使?用令牌來授權,在任一時刻只能有一個執行線程訪問代碼的臨界區域。臨界區域是指執行數據更新的代碼需要獨占式地執行。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個線程在訪問它,也就是說信號量是用來協調進程對共享資源的訪問的。其中共享內存的使用就要用到信號量。
信號量只能進行兩種操作等待和發送信號,PV操作,即P(sv)和V(sv),P申請資源,則將可用資源數-1,V釋放資源,則將可用資源數+1。
內核為每個信號量集合維護著一個semid_ds結構:
struct semid_ds {struct ipc_perm sem_perm;unsigned short sem_nsems; //該集合的信號量數目time_t sem_otime;time_t sem_ctime; };每個信號量都有一個無名的結構:
unsigned short semval; /* semaphore value */unsigned short semzcnt; /* # waiting for zero */unsigned short semncnt; /* # waiting for increase */pid_t sempid; /* process that did last op */當我們想使用信號量時,首先要通過調用函數semget來獲得一個信號量ID:
#include<sys/sem.h> int semget(key_t key,int nsems,int flag); //成功,返回信號量ID,出錯返回-1semctl函數包含了多種信號量操作
int semctl(int semid,int semnum,int cmd,.../* union semun arg */); //第四個參數是可選的,取決于請求的命令,如果使用該參數,則其類型是semun,它是多個命令特定的聯合。 union semun {int val; //for SETVAL;struct semid_ds *buf; //for IPC_STAT and IPC_SET;unsigned short *array; //for GETALL and SETALL };我們通常使用的:IPC_RMID:從系統中刪除該信號量集合
SETVAL:設置成員semnum的semval值,該值由arg.val指定
函數semop自動執行信號量集合上的操作數組。
int semop(int semid,struct sembuf semoparray[],size_t nops); //成功,返回0,失敗,返回-1;semoparray是一個指針,指向由sembuf結構表示的信號量操作數組,nops規定該數組中操作的數量 struct sembuf {unsigned short sem_num; //0,1,2,3,....short sem_op; //(負值,0,正值)-1,0,1short sem_flg; //IPC_NOWAIT,SEM_UNDO };對集合中每個成員的操作由相應的sem_op值規定。此值可以為負值,0,正值。最易于處理的是為正值,說明需要釋放資源,則sem_op的值會加到信號量值上,如果指定了undo標志,則從此信號量調整之后的值上減去sem_op;如果sem_op是負值,說明需要申請資源,則信號量會減去sem_op的絕對值,如果指定undo標志,則sem_op的絕對值也加到信號量的調整值上。sem_op為0,表示調用進程希望等待到該信號量值為0。
對于信號量調整,如果在進程終止時,它占用了經由信號量分配的資源,那么就會成為一個問題。無論何時只要為信號量操作指定了SEM_UNDO標志,然后分配資源(sem_op< 0),那么內核就會記住該特定信號量,分配給調用進程多少資源。對每個操作都指定SEM_UNDO,以處理在未釋放資源條件下進程終止的情況。
信號量主要解決互斥與同步問題,下面舉個栗子:(實現父子進程輸出成對AA或BB)
//comm.h #ifndef _COMM_H_ #define _COMM_H_#include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h>#define PATHNAME "." #define PROJ_ID 0X6666 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; };int CreateSem(int nums); int GetSem(int nums); int DestroySem(int semid); int initSem(int semid,int nums,int initval); int SemP(int semid,int who); int SemV(int semid,int who);#endif //_COMM_H_ #include"comm.h"static int CommSemSet(int nsems,int flags) {key_t key = ftok(PATHNAME,PROJ_ID);if(key < 0){//printf("%d\n", key);perror("ftok");return -1;}int semid = semget(key,nsems,flags);if(semid < 0){perror("semget");return -2;}return semid; }int CreateSemSet(int nums) {return CommSemSet(nums,IPC_CREAT|IPC_EXCL|0666); }int GetSem(int nums) {return CommSemSet(nums,IPC_CREAT); } int DestroySem(int semid) {if(semctl(semid,0,IPC_RMID) < 0){perror("semctl");return -1;}return 0; }int initSem(int semid,int nums,int initval) {union semun _un;_un.val = initval;if(semctl(semid,nums,SETVAL,_un) < 0){perror("semctl");return -1;}return 0; }static int CommPV(int semid,int who,int op) {struct sembuf _sem;_sem.sem_num = who;_sem.sem_op = op;_sem.sem_flg = 0;if(semop(semid,&_sem,1) < 0){perror("semop");return -1;} return 0; } int SemP(int semid,int who) {return CommPV(semid,who,-1); } int SemV(int semid,int who) {return CommPV(semid,who,1); } //sem.c #include"comm.h"int main() {int semid = CreateSemSet(1);initSem(semid,0,1); pid_t id = fork();if(id == 0)//child{int _semid = GetSem(0);while(1){SemP(_semid,0);printf("A");fflush(stdout);usleep(123456);printf("A");fflush(stdout);usleep(345678); SemV(_semid,0);}}else{while(1){SemP(semid,0);printf("B");fflush(stdout);usleep(234567);printf("B");fflush(stdout);usleep(456789);// usleep(121212);SemV(semid,0);}wait(NULL);}DestroySem(semid);printf("sem quit!\n");return 0; } //Makefile sem:sem.c comm.cgcc -o $@ $^ .PHONY:clean clean:rm -f sem運行結果:
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[Linux]信号量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dnf什么职业最好
- 下一篇: 和平精英僚机物资有哪些