linux的ipc訊號量簡單例項
阿新 • • 發佈:2019-01-22
訊號量實現程序間訪問互斥的資源測試例子。
主要涉及到的函式及原型如下(加粗、顏色表示要重點關心的上下文相關變數)
1: key_tftok(char *fileName, int id);//目的獲取key值
2: intsemget(key_t key, int nsems, int semflg)//目的獲取id
3:int semctl(int semid, int semnum, int cmd, union semunarg)//目的設定訊號量的值,獲取訊號量的值等等,功能通過cmd變數控制
//其中semunarg必須由使用者自身定義,格式如下
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
//other linux specific
};
4: int semop(int semid, struct sembuf *sops, unsign ednsops)//目的改變訊號量的值,在sembuf中。
可通過每個函式大體功能,man手冊中查詢一些說明,進行研究測試。
以下測試程式碼非常簡單,僅僅是為了熟悉api的基本功能,如果有錯誤和需要說明的地方,歡迎指正。
#include <sys/types.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
union semun {//semctl函式的第三個引數結構定義,現只關心設定val,其它成員可忽視,起到初始化資源數目的作用
int val;
// struct semid_ds *buf;
// unsigned short *array;
// struct seminfo *__buf;
};
int sem_init(int semid, int initval)//初始化訊號量 init val
{
union semun arg;
arg.val = initval;
semctl(semid, 0, SETVAL, arg);//SETVAL 是semctl的cmd引數,意思是設定訊號量為arg.val的值,0是訊號量中第1個資源的下標
//fixme if some error
return 0;
}
int creat_sem(char *fileName)//建立一個訊號燈,訊號量預設寫了1個,如果沒有該訊號量,建立,如果有,獲取id
{
int id;
key_t key;
key = ftok(fileName, 1);
if (key < 0) {
perror("ftok()");
key = 5;//any number just for test
}
if ((id = semget(key, 1, IPC_CREAT | IPC_EXCL |0660)) < 0) {//1個訊號量 creat? or exist?
if ((id = semget(key, 1, IPC_CREAT | 0660)) < 0) {//1個訊號量 if exist,only get the id
printf("semget error: id = %d\n", id);
}
printf("sem allready exist: id = %d\n", id);
} else {//init the number when first use
sem_init(id, 0);
}
return id;
}
void P(int semid)//申請資源,資源數sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in p(s)\n");
}
}
void V(int semid)//釋放資源,資源數sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in v(s)\n");
}
}
void showStat(int semid)
{
int ret = semctl(semid, 0, GETVAL, 0);
printf("now %d val is %d\n", semid, ret);
}
int main(int argc, char **argv)
{
int sem_id0, sem_id1;
if (fork() == 0) {//子程序 程序1
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
V(sem_id1);
while (1) {
P(sem_id0);
printf("working : process11111\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(1);
V(sem_id1);
}
} else {//父程序 程序2
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
sleep(2);
while (1) {
P(sem_id1);
printf("working : process2222222222\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(2);
V(sem_id0);
}
}
return 0;
}
主要涉及到的函式及原型如下(加粗、顏色表示要重點關心的上下文相關變數)
1: key_tftok(char *fileName, int id);//目的獲取key值
2: intsemget(key_t key, int nsems, int semflg)//目的獲取id
3:int semctl(int semid, int semnum, int cmd, union semunarg)//目的設定訊號量的值,獲取訊號量的值等等,功能通過cmd變數控制
//其中semunarg必須由使用者自身定義,格式如下
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
//other linux specific
};
4: int semop(int semid, struct sembuf *sops, unsign ednsops)//目的改變訊號量的值,在sembuf中。
可通過每個函式大體功能,man手冊中查詢一些說明,進行研究測試。
以下測試程式碼非常簡單,僅僅是為了熟悉api的基本功能,如果有錯誤和需要說明的地方,歡迎指正。
#include <sys/types.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
union semun {//semctl函式的第三個引數結構定義,現只關心設定val,其它成員可忽視,起到初始化資源數目的作用
int val;
// struct semid_ds *buf;
// unsigned short *array;
// struct seminfo *__buf;
};
int sem_init(int semid, int initval)//初始化訊號量 init val
{
union semun arg;
arg.val = initval;
semctl(semid, 0, SETVAL, arg);//SETVAL 是semctl的cmd引數,意思是設定訊號量為arg.val的值,0是訊號量中第1個資源的下標
//fixme if some error
return 0;
}
int creat_sem(char *fileName)//建立一個訊號燈,訊號量預設寫了1個,如果沒有該訊號量,建立,如果有,獲取id
{
int id;
key_t key;
key = ftok(fileName, 1);
if (key < 0) {
perror("ftok()");
key = 5;//any number just for test
}
if ((id = semget(key, 1, IPC_CREAT | IPC_EXCL |0660)) < 0) {//1個訊號量 creat? or exist?
if ((id = semget(key, 1, IPC_CREAT | 0660)) < 0) {//1個訊號量 if exist,only get the id
printf("semget error: id = %d\n", id);
}
printf("sem allready exist: id = %d\n", id);
} else {//init the number when first use
sem_init(id, 0);
}
return id;
}
void P(int semid)//申請資源,資源數sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in p(s)\n");
}
}
void V(int semid)//釋放資源,資源數sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in v(s)\n");
}
}
void showStat(int semid)
{
int ret = semctl(semid, 0, GETVAL, 0);
printf("now %d val is %d\n", semid, ret);
}
int main(int argc, char **argv)
{
int sem_id0, sem_id1;
if (fork() == 0) {//子程序 程序1
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
V(sem_id1);
while (1) {
P(sem_id0);
printf("working : process11111\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(1);
V(sem_id1);
}
} else {//父程序 程序2
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
sleep(2);
while (1) {
P(sem_id1);
printf("working : process2222222222\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(2);
V(sem_id0);
}
}
return 0;
}