PV原子操做的具體定義以下:(好好理解,很重要的啊)git
● P操做:若是有可用的資源(信號量值>0),則此操做所在的進程佔用一個資源(此時信號量值減1,進入臨界區代碼);若是沒有可用的資源(信號量值=0),則此操做所在的進程被阻塞直到系統將資源分配給該進程(進入等待隊列,一直等到資源輪到該進程)。github
● V操做:若是在該信號量的等待隊列中有進程在等待資源,則喚醒一個阻塞進程;若是沒有進程等待它,則釋放一個資源(即信號量值加1)。數組
semget(獲得一個信號量集標識符緩存 或建立一個信號量集對象)數據結構 |
||
所需頭文件函數 |
#include <sys/types.h>spa #include <sys/ipc.h>線程 #include <sys/sem.h>code |
|
函數說明對象 |
獲得一個信號量集標識符或建立一個信號量集對象並返回信號量集標識符 |
|
函數原型 |
int semget(key_t key, int nsems, int semflg) |
|
函數傳入值 |
key |
0(IPC_PRIVATE):會創建新信號量集對象 |
大於0的32位整數:視參數semflg來肯定操做,一般要求此值來源於ftok返回的IPC鍵值 |
||
nsems |
建立信號量集中信號量的個數,該參數只在建立信號量集時有效 |
|
msgflg |
0:取信號量集標識符,若不存在則函數會報錯 |
|
IPC_CREAT:當semflg&IPC_CREAT爲真時,若是內核中不存在鍵值與key相等的信號量集,則新建一個信號量集;若是存在這樣的信號量集,返回此信號量集的標識符 |
||
IPC_CREAT|IPC_EXCL:若是內核中不存在鍵值與key相等的信號量集,則新建一個消息隊列;若是存在這樣的信號量集則報錯 |
||
函數返回值 |
成功:返回信號量集的標識符 |
|
出錯:-1,錯誤緣由存於error中 |
||
附加說明 |
上述semflg參數爲模式標誌參數,使用時須要與IPC對象存取權限(如0600)進行|運算來肯定信號量集的存取權限 |
|
錯誤代碼 |
EACCESS:沒有權限 EEXIST:信號量集已經存在,沒法建立 EIDRM:信號量集已經刪除 ENOENT:信號量集不存在,同時semflg沒有設置IPC_CREAT標誌 ENOMEM:沒有足夠的內存建立新的信號量集 ENOSPC:超出限制 |
semop(完成對信號量的P操做或V操做) |
|
所需頭文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> |
函數說明 |
對信號量集標識符爲semid中的一個或多個信號量進行P操做或V操做 |
函數原型 |
int semop(int semid, struct sembuf *sops, unsigned nsops) |
函數傳入值 |
semid:信號量集標識符 |
sops:指向進行操做的信號量集結構體數組的首地址,此結構的具體說明以下: struct sembuf { short semnum; /*信號量集合中的信號量編號,0表明第1個信號量*/ short val;/*若val>0進行V操做信號量值加val,表示進程釋放控制的資源 */ /*若val<0進行P操做信號量值減val,若(semval-val)<0(semval爲該信號量值),則調用進程阻塞,直到資源可用;若設置IPC_NOWAIT不會睡眠,進程直接返回EAGAIN錯誤*/ /*若val==0時阻塞等待信號量爲0,調用進程進入睡眠狀態,直到信號值爲0;若設置IPC_NOWAIT,進程不會睡眠,直接返回EAGAIN錯誤*/ short flag; /*0 設置信號量的默認操做*/ /*IPC_NOWAIT設置信號量操做不等待*/ /*SEM_UNDO 選項會讓內核記錄一個與調用進程相關的UNDO記錄,若是該進程崩潰,則根據這個進程的UNDO記錄自動恢復相應信號量的計數值*/ }; |
|
nsops:進行操做信號量的個數,即sops結構變量的個數,需大於或等於1。最多見設置此值等於1,只完成對一個信號量的操做 |
|
函數返回值 |
成功:返回信號量集的標識符 |
出錯:-1,錯誤緣由存於error中 |
|
錯誤代碼 |
E2BIG:一次對信號量個數的操做超過了系統限制 EACCESS:權限不夠 EAGAIN:使用了IPC_NOWAIT,但操做不能繼續進行 EFAULT:sops指向的地址無效 EIDRM:信號量集已經刪除 EINTR:當睡眠時接收到其餘信號 EINVAL:信號量集不存在,或者semid無效 ENOMEM:使用了SEM_UNDO,但無足夠的內存建立所需的數據結構 ERANGE:信號量值超出範圍 |
semctl (獲得一個信號量集標識符或建立一個 信號量集對象) |
|
所需頭文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> |
函數說明 |
獲得一個信號量集標識符或建立一個信號量集對象並返回信號量集標識符 |
函數原型 |
int semctl(int semid, int semnum, int cmd, union semun arg) |
函數傳入值 |
semid 信號量集標識符 |
semnum |
信號量集數組上的下標,表示某一個信號量 |
cmd |
見下文表15-4 |
arg |
union semun { short val; /*SETVAL用的值*/ struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds結構*/ unsigned short* array; /*SETALL、GETALL用的數組值*/ struct seminfo *buf; /*爲控制IPC_INFO提供的緩存*/ } arg; |
函數返回值 |
成功:大於或等於0,具體說明請參照表15-4 |
出錯:-1,錯誤緣由存於error中 |
|
附加說明 |
semid_ds結構見上文信號量集內核結構定義 |
錯誤代碼 |
EACCESS:權限不夠 EFAULT:arg指向的地址無效 EIDRM:信號量集已經刪除 EINVAL:信號量集不存在,或者semid無效 EPERM:進程有效用戶沒有cmd的權限 ERANGE:信號量值超出範圍 |
利用信號量封裝得PV原子操做
代碼實現:
https://github.com/manmao/Module/tree/master/Semaphore-PV
能夠使用信號量,也能夠使用互斥鎖
pthread_mutex_t默認屬性是:PTHREAD_PROCESS_PRIVATE,單進程內部使用,適用於同一個進程多個線程操做,可是能夠修改pthread_mutext_t的屬性爲PTHREAD_PROCESS_SHARED,讓其能夠適用於多個進程的互斥
修改互斥鎖的屬性爲進程共享
pthread_mutexattr_t mutexattr; pthread_mutex_t mutex; pthread_mutexattr_init(&mutexattr); pthread_mutexattr_setpshared(&mutexattr,PTHREAD_PROCESS_SHARED); //設置爲進程共享 pthread_mutex_init(&mutex,&mutexattr);
pthread_mutex_t 實現進程互斥例子:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> typedef struct _FOO { int nCount; int nData; }FOO,*PFOO; int main(int argc,char *argv[]) { FOO *ptr; pid_t pid; pthread_mutexattr_t mutexattr; pthread_mutex_t mutex; pthread_mutexattr_init(&mutexattr); pthread_mutexattr_setpshared(&mutexattr,PTHREAD_PROCESS_SHARED); //設置爲進程共享 pthread_mutex_init(&mutex,&mutexattr); ptr = (PFOO)mmap(NULL,sizeof(FOO),PROT_READ | PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0); //匿名內存映射,讓父子進程都操做ptr指向的內存區,若是不使用共享內存,則父子進程的ptr指向的是各自的內存空間 ptr->nCount = 1; ptr->nData = 2; printf("%d,%d\n",ptr->nCount,ptr->nData); if( (pid = fork()) < 0) { printf("fork error\n"); return -1; } else if( 0 == pid) //子進程 { for(int i = 0;i<3;i++) { pthread_mutex_lock(&mutex); ptr->nCount++; printf("child ++ === %d\n",ptr->nCount); pthread_mutex_unlock(&mutex); usleep(1000); } } else //父進程 { for(int i = 0;i<3;i++) { pthread_mutex_lock(&mutex); ptr->nCount += 2; printf("parent +2 === %d\n",ptr->nCount); pthread_mutex_unlock(&mutex); usleep(1000); } } waitpid(pid,NULL,0); munmap(NULL,sizeof(FOO)); return 0; }
pthread_mutexattr_t 操做API:
pthread_mutexattr_init:配置初始化 pthread_mutexattr_destroy:刪除配置初始化接口申請的資源 pthread_mutexattr_setpshared:設置mutex是否進程間共享 pthread_mutexattr_settype:設置類型,如遞歸調用,錯誤檢測等。 pthread_mutexattr_setprotocol:設置是否支持優先級翻轉 pthread_mutexattr_setprioceiling:設置獲取信號量的任務運行在最高優先級。