百度百科:https://baike.baidu.com/item/%E4%BF%A1%E5%8F%B7%E9%87%8F%E6%9C%BA%E5%88%B6/9175303
信號(hào)量S是一個(gè)整數(shù),S大于等于零是代表可供并發(fā)進(jìn)程使用的資源實(shí)體數(shù),當(dāng)S小于零時(shí)則表示正在等待使用臨界區(qū)的進(jìn)程數(shù)。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Dijkstra同時(shí)提出了對信號(hào)量操作的PV原語:
P原語:P是荷蘭語Proberen(測試)的首字母。為阻塞原語,負(fù)責(zé)把當(dāng)前進(jìn)程由運(yùn)行狀態(tài)轉(zhuǎn)換為阻塞狀態(tài),直到另外一個(gè)進(jìn)程喚醒它。操作為:申請一個(gè)空閑資源(把信號(hào)量減1),若成功,則退出;若失敗,則該進(jìn)程被阻塞;
V原語:V是荷蘭語Verhogen(增加)的首字母。為喚醒原語,負(fù)責(zé)把一個(gè)被阻塞的進(jìn)程喚醒,它有一個(gè)參數(shù)表,存放著等待被喚醒的進(jìn)程信息。操作為:釋放一個(gè)被占用的資源(把信號(hào)量加1),如果發(fā)現(xiàn)有被阻塞的進(jìn)程,則選擇一個(gè)喚醒之。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
具體PV原語對信號(hào)量的操作可以分為三種情況:
1)把信號(hào)量視為一個(gè)加鎖標(biāo)志位,實(shí)現(xiàn)對一個(gè)共享變量的互斥訪問。
實(shí)現(xiàn)過程:
P(mutex); // mutex的初始值為1 訪問該共享數(shù)據(jù);
V(mutex);
非臨界區(qū)
2)把信號(hào)量視為是某種類型的共享資源的剩余個(gè)數(shù),實(shí)現(xiàn)對一類共享資源的訪問。
實(shí)現(xiàn)過程:
P(resource); // resource的初始值為該資源的個(gè)數(shù)N 使用該資源;
V(resource); 非臨界區(qū)
3)把信號(hào)量作為進(jìn)程間的同步工具
實(shí)現(xiàn)過程:
臨界區(qū)C1;
P(S);
V(S);
臨界區(qū)C2;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
P原語操作的動(dòng)作是:
(1)S減1;
(2)若S減1后仍大于或等于零,則進(jìn)程繼續(xù)執(zhí)行;
(3)若S減1后小于零,則該進(jìn)程被阻塞后進(jìn)入與該信號(hào)相對應(yīng)的隊(duì)列中,然后轉(zhuǎn)進(jìn)程調(diào)度。
V原語操作的動(dòng)作是:
(1)S加1;
(2)若相加結(jié)果大于零,則進(jìn)程繼續(xù)執(zhí)行;
(3)若相加結(jié)果小于或等于零,則從該信號(hào)的等待隊(duì)列中喚醒一等待進(jìn)程,然后再返回原進(jìn)程繼續(xù)執(zhí)行或轉(zhuǎn)進(jìn)程調(diào)度。
PV操作對于每一個(gè)進(jìn)程來說,都只能進(jìn)行一次,而且必須成對使用。在PV原語執(zhí)行期間不允許有中斷的發(fā)生。
信號(hào)量機(jī)制分?整型信號(hào)量機(jī)制、記錄型信號(hào)量機(jī)制、and型信號(hào)量機(jī)制、信號(hào)量集。
整型信號(hào)量是一種最簡單的信號(hào)量,主要用于解決并發(fā)程序互斥訪問臨界資源問題。
記號(hào)信號(hào)量在整型信號(hào)量的舉出上進(jìn)行了改進(jìn),讓不能進(jìn)入臨界區(qū)的進(jìn)程“讓權(quán)等待”,即進(jìn)程狀態(tài)有運(yùn)行轉(zhuǎn)換為阻塞狀態(tài),進(jìn)程進(jìn)入阻塞隊(duì)列中等待。
AND型信號(hào)量集是將進(jìn)程在運(yùn)行中所需要的臨界資源全部一次性分配給進(jìn)程,等進(jìn)程用完后再全部一次釋放。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Linux信號(hào)量集
定義:保護(hù)共享資源,使得資源在一個(gè)時(shí)刻只有一個(gè)進(jìn)程(線程)擁有
原理:信號(hào)量值為正時(shí)說明空閑,若為0或負(fù)值則說明被占用
分類:內(nèi)核信號(hào)量與用戶信號(hào)量,用戶信號(hào)量分為POXIS信號(hào)量和SYSTEMV信號(hào)量,POXIS信號(hào)量分為有名信號(hào)量和無名信號(hào)量
內(nèi)核信號(hào)量:
#include<asm/semaphore.h>
void sema_init(struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem); //初始值1
void init_MUTEX_LOCKED(struct semaphore *sem); //初始值0
void down(struct semaphore *sem); //可睡眠
int down_interruptible(struct semaphore *sem); //可中斷
int down_trylock(struct semaphore *sem); //m非阻塞
void up(struct semaphore *sem);
SYSTEMV信號(hào)量:
#include <sys/sem.h>
int semget(key_t key, int nsems, int oflag);
int semop(int semid, struct sembuf *opsptr, size_t nops);
int semctl(int semid, int semum, int cmd,...);
POSIX無名信號(hào)量
#include<semaphore.h>
sem_t sem;
int sem_init(sem_t *sem, int pshared, unsigned int val); //pshared為0則線程間共享,pshared為1則父子進(jìn)程共享
int sem_wait(sem_t *sem); //阻塞
int sem_trywait(sem_t *sem); //非阻塞
int sem_post(sem_t *sem);
int sem_destroy(sem_t *sem);
進(jìn)程間共享則sem必須放在共享內(nèi)存區(qū)域(mmap, shm_open, shmget),父進(jìn)程的全局變量、堆、棧中存儲(chǔ)是不行的
POSIX有名信號(hào)量
sem_t *sem_open(const char *name, int oflag, mode_t mode, int val);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
每個(gè)open的位置都要close和unlink,但只有最后執(zhí)行的unlink生效