程序通訊-訊號量semaphore
阿新 • • 發佈:2019-02-06
semaphore:訊號量 標頭檔案:include <sys/sem.h>
int semget(key_t key,int num_sems,int sem_flags);建立或獲取一個訊號量組:若成功返回訊號量集ID,失敗返回-1
功能:建立一個新訊號量或取得一個已有訊號量的鍵。
引數:key:不相關的程序可以通過該整數值訪問同一個訊號量。
num_sems:指定需要的訊號量的數目。
sem_flags:一組標誌。
返回:成功時返回一個正數;失敗返回-1.
int semop(int semid, struct sembuf semoparray[],size_t numops);對訊號量組進行操作,改變訊號量的值:成功返回0,失敗返回-1
int semop(int sm_id, struct sembuf *sem_ops, size_t num_sem_ops);
功能:用於改變訊號量的值。
引數:sm_id:由semget返回的訊號量識別符號。
sem_ops:指向要操作的結構陣列的指標。
num_sem_ops:要操作的結構陣列的元素個數。
返回:成功返回0;失敗返回-1.
int semctl(int semid, int sem_num, int cmd, union semun arg);控制訊號量的相關資訊
功能:用來直接控制訊號量資訊。
引數:sem_id:由semget返回的訊號量識別符號。
sem_num:訊號量編號。
comd:要採取的操作,一些命令可以查資料。
返回:成功返回0;失敗返回-1.
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提供的快取
};
當semget建立新的訊號量集合,必須指定集合中訊號量的個數(num_sems),通常為1,如果引用一個現有的集合,則將num_sems指定為0
struct sembuf
{
short sem_num; // 訊號量組中對應的序號,0~sem_nums-1
short sem_op; // 訊號量值在一次操作中的改變數
short sem_flg; // IPC_NOWAIT, SEM_UNDO
}
訊號量semaphore,它是一個計數器,訊號量用於實現程序間的互斥與同步,而不是用於儲存程序間通訊資料。
1.特點
訊號量用於程序間同步,若要在程序間傳遞資料需要結合共享記憶體。
訊號量基於作業系統的 PV 操作,程式對訊號量的操作都是原子操作。
每次對訊號量的 PV 操作不僅限於對訊號量值加 1 或減 1,而且可以加減任意正整數。
支援訊號量組。
2.原型
最簡單的訊號量是隻能取0和1的變數,這也是訊號量最常見的一種形式,叫做二值訊號量(Binary Semaphore)。
而可以取多個正整數的訊號量被稱為通用訊號量。
在semctl函式中的命令有多種,這裡就說兩個常用的:
SETVAL:用於初始化訊號量為一個已知的值,所需要的值作為聯合semun的val成員來傳遞,
在訊號量第一次使用之前需要設定訊號量。
IPC_RMID:刪除一個訊號量集合,如果不刪除訊號量,它將繼續在系統中存在,即使程式已經退出,
int semget(key_t key,int num_sems,int sem_flags);建立或獲取一個訊號量組:若成功返回訊號量集ID,失敗返回-1
功能:建立一個新訊號量或取得一個已有訊號量的鍵。
引數:key:不相關的程序可以通過該整數值訪問同一個訊號量。
num_sems:指定需要的訊號量的數目。
sem_flags:一組標誌。
返回:成功時返回一個正數;失敗返回-1.
int semop(int semid, struct sembuf semoparray[],size_t numops);對訊號量組進行操作,改變訊號量的值:成功返回0,失敗返回-1
int semop(int sm_id, struct sembuf *sem_ops, size_t num_sem_ops);
功能:用於改變訊號量的值。
引數:sm_id:由semget返回的訊號量識別符號。
sem_ops:指向要操作的結構陣列的指標。
num_sem_ops:要操作的結構陣列的元素個數。
返回:成功返回0;失敗返回-1.
int semctl(int semid, int sem_num, int cmd, union semun arg);控制訊號量的相關資訊
功能:用來直接控制訊號量資訊。
引數:sem_id:由semget返回的訊號量識別符號。
sem_num:訊號量編號。
comd:要採取的操作,一些命令可以查資料。
返回:成功返回0;失敗返回-1.
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提供的快取
};
當semget建立新的訊號量集合,必須指定集合中訊號量的個數(num_sems),通常為1,如果引用一個現有的集合,則將num_sems指定為0
struct sembuf
{
short sem_num; // 訊號量組中對應的序號,0~sem_nums-1
short sem_op; // 訊號量值在一次操作中的改變數
short sem_flg; // IPC_NOWAIT, SEM_UNDO
}
訊號量semaphore,它是一個計數器,訊號量用於實現程序間的互斥與同步,而不是用於儲存程序間通訊資料。
1.特點
訊號量用於程序間同步,若要在程序間傳遞資料需要結合共享記憶體。
訊號量基於作業系統的 PV 操作,程式對訊號量的操作都是原子操作。
每次對訊號量的 PV 操作不僅限於對訊號量值加 1 或減 1,而且可以加減任意正整數。
支援訊號量組。
2.原型
最簡單的訊號量是隻能取0和1的變數,這也是訊號量最常見的一種形式,叫做二值訊號量(Binary Semaphore)。
而可以取多個正整數的訊號量被稱為通用訊號量。
在semctl函式中的命令有多種,這裡就說兩個常用的:
SETVAL:用於初始化訊號量為一個已知的值,所需要的值作為聯合semun的val成員來傳遞,
在訊號量第一次使用之前需要設定訊號量。
IPC_RMID:刪除一個訊號量集合,如果不刪除訊號量,它將繼續在系統中存在,即使程式已經退出,
它可能在你下次執行此程式時引發問題,而且訊號量是一種有限的資源。
#include<stdio.h> #include<stdlib.h> #include<sys/sem.h> //聯合體,用於訊號量semctl初始化 union semun { int val; /*for SETVAL*/ struct semid_ds *buf; unsigned short *array; }; //初始化訊號量 int init_sem(int sem_id, int value) { union semun tmp; tmp.val = value; if(semctl(sem_id, 0, SETVAL, tmp) == -1) { perror("Init Semaphore Error"); return -1; } return 0; } //P操作:若訊號量值為1,獲取資源並將訊號量值-1,若訊號量值為0,程序掛起等待 int sem_p(int sem_id) { struct sembuf sbuf; sbuf.sem_num = 0; //序號 sbuf.sem_op = -1; //P操作 sbuf.sem_flg = SEM_UNDO; if(semop(sem_id, &sbuf, 1) == -1) { perror("P operation Error"); return -1; } return 0; } //V操作:釋放資源並將訊號量值+1,如果有程序正在掛起等待,則喚醒它們 int sem_v(int sem_id) { struct sembuf sbuf; sbuf.sem_num = 0; //序號 sbuf.sem_op = 1; //V操作 sbuf.sem_flg = SEM_UNDO; if(semop(sem_id, &sbuf, 1) == -1) { perror("V operation Error"); return -1; } return 0; } //刪除訊號量集 int del_sem(int sem_id) { union semun tmp; if(semctl(sem_id, 0, IPC_RMID, tmp) == -1) { perror("Delete Semaphore Error"); return -1; } return 0; } int main() { int sem_id; // 訊號量集ID key_t key; //ID號 pid_t pid; /************************************************************************ 系統建立IPC通訊(訊息佇列.訊號量和共享記憶體)時必須指定一個ID值,該id值通過ftok函式得到 原型:key_t ftok(const char * fname, int id) 引數:fname是檔案路徑一般取當前目錄,id是子ID號 返回值:一般將檔案的索引節點取出加上id號為返回值 檔案的索引節點ls -a檢視 eg:如指定檔案的索引節點號為65538,換算成16進製為0x010002,而你指定的ID值為38,換算成16進位制 為0x26,則最後的key_t返回值為0x26010002。 *************************************************************************/ if((key = ftok(".", 'z')) < 0)// 獲取key值 { perror("ftok error"); exit(1); } //建立訊號量集,其中只有一個訊號量 if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1) { perror("semget error"); exit(1); } //初始化:初值設為0資源被佔用 init_sem(sem_id, 0); if((pid = fork()) == -1) perror("Fork Error"); else if(pid == 0) //子程序 { sleep(2); printf("Process child: pid=%d\n", getpid()); sem_v(sem_id); //釋放資源 } else //父程序 { sem_p(sem_id); //等待資源 printf("Process father: pid=%d\n", getpid()); sem_v(sem_id); //釋放資源 del_sem(sem_id); //刪除訊號量集 } return 0; }