System信號量集主要API
#include
#include
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);semget
int semget(key_t key, int nsems, int semflg);
/** 示例1: 封裝一個創(chuàng)建一個信號量集函數(shù)
該信號量集包含1個信號量;權(quán)限為0666
**/int sem_create(key_t key){int semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);if (semid == -1)err_exit("sem_create error");return semid;}
/** 示例2: 打開一個信號量集
nsems(信號量數(shù)量)可以填0,semflg(信號量權(quán)限)也可以填0, 表示使用默認的權(quán)限打開
**/int sem_open(key_t key){int semid = semget(key, 0, 0);if (semid == -1)err_exit("sem_open error");return semid;}int semctl(int semid, int semnum, int cmd, ...);
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; /* Buffer for IPC_INFO (Linux-specific)*/};
//struct semid_ds : Linux內(nèi)核為System V信號量維護的數(shù)據(jù)結(jié)構(gòu)struct semid_ds{struct ipc_perm sem_perm; /* Ownership and permissions */time_t sem_otime; /* Last semop time */time_t sem_ctime; /* Last change time */unsigned long sem_nsems; /* No. of semaphores in set */};
/** 示例1: 將信號量集semid中的第一個信號量的值設(shè)置成為value(SETVAL)
注意: semun聯(lián)合體需要自己給出(從man-page中拷貝出來即可)
**/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; /* Buffer for IPC_INFO(Linux-specific) */};int sem_setval(int semid, int value){union semun su;su.val = value;if (semctl(semid, 0, SETVAL, su) == -1)err_exit("sem_setval error");return 0;}
/** 示例2: 獲取信號量集中第一個信號所關(guān)聯(lián)的值(GETVAL)
注意: 此時第四個參數(shù)可以不填, 而信號量所關(guān)聯(lián)的值可以通過semctl的返回值返回(the value of semval.)
**/int sem_getval(int semid){int value = semctl(semid, 0, GETVAL);if (value == -1)err_exit("sem_getval error");return value;return 0;}
/** 示例3: 刪除一個信號量集(注意是刪除整個集合)
IPC_RMID Immediately remove(立刻刪除) the semaphore set, awakening all processes blocked in semop(2) calls on the set (with an error return and errno set to EIDRM)[然后喚醒所有阻塞在該信號量上的進程]. The argument semnum is ignored[忽略第二個參數(shù)].**/int sem_delete(int semid){if (semctl(semid, 0, IPC_RMID) == -1)err_exit("sem_delete error");return 0;}//測試代碼int main(int argc,char *argv[]){int semid = sem_create(0x1234); //創(chuàng)建一個信號量集sem_setval(semid, 500); //設(shè)置值cout << sem_getval(semid) << endl; //獲取值sleep(10);sem_delete(semid); //刪除該集合} /**
示例4: 獲取/設(shè)置信號量的權(quán)限
注意:一定要設(shè)定struct semid_ds結(jié)構(gòu)體, 以指定使用semun的哪個字段
**/int sem_getmode(int semid){union semun su;// 注意: 下面這兩行語句一定要設(shè)定.// (告訴內(nèi)核使用的semun的哪個字段)struct semid_ds sd;su.buf = &sd;//if (semctl(semid, 0, IPC_STAT, su) == -1)err_exit("sem_getmode error");printf("current permissions is: %o\n", su.buf->sem_perm.mode);return 0;}int sem_setmode(int semid, char *mode){union semun su;// 注意: 下面這兩行語句一定要設(shè)定.// (告訴內(nèi)核使用的semun的哪個字段)struct semid_ds sd;su.buf = &sd;//sscanf(mode, "%o", (unsigned int *)&su.buf->sem_perm.mode);if (semctl(semid, 0, IPC_SET, su) == -1)err_exit("sem_setmode error");return 0;}[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片int semop(int semid, struct sembuf *sops, unsigned nsops);[cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片//sembuf結(jié)構(gòu)體struct sembuf{unsigned short sem_num; /*semaphore number:信號量的編號(從0開始)*/short sem_op; /* semaphore operation(+1, 0, -1) */short sem_flg; /* operation flags: 常用取值為SEM_UNDO(解釋見下) */};
/** 示例: P,V操作封裝**可以將sembuf的第三個參數(shù)設(shè)置為IPC_NOWAIT/0, 以查看程序的狀態(tài)的變化**/int sem_P(int semid){struct sembuf sops = {0, -1, SEM_UNDO};if (semop(semid, &sops, 1) == -1)err_exit("sem_P error");return 0;}int sem_V(int semid){struct sembuf sops = {0, +1, SEM_UNDO};if (semop(semid, &sops, 1) == -1)err_exit("sem_V error");return 0;}
下面我們封裝一個信號量操作函數(shù)工具,將主要的操作封裝起來,可以像命令一樣使用,
Linux進程間通信(IPC)編程實踐(九)System V信號量
,電腦資料
《Linux進程間通信(IPC)編程實踐(九)System V信號量》(http://www.stanzs.com)。/** 信號量綜合運用示例:
編譯完成之后, 直接運行./semtool, 程序?qū)⒋蛴≡摴ぞ叩挠梅?下面的這些函數(shù)調(diào)用, 只不過是對上面所封裝函數(shù)的稍稍改動, 理解起來并不困難;
**///semtool.cpp#include "Usage.h"int main(int argc,char *argv[]){int pt = getopt(argc, argv, "cdpvs:gfm:");if (opt == '?')exit(EXIT_FAILURE);else if (opt == -1){usage();exit(EXIT_FAILURE);}key_t key = ftok(".", 's');int semid;switch (opt){case 'c':sem_create(key);break;case 'd':semid = sem_open(key);sem_delete(semid);break;case 'p':semid = sem_open(key);sem_P(semid);sem_getval(semid);break;case 'v':semid = sem_open(key);sem_V(semid);sem_getval(semid);break;case 's':semid = sem_open(key);sem_setval(semid, atoi(optarg));sem_getval(semid);break;case 'g':semid = sem_open(key);sem_getval(semid);break;case 'f':semid = sem_open(key);sem_getmode(semid);break;case 'm':semid = sem_open(key);sem_setmode(semid, argv[2]);sem_getmode(semid);break;default:break;}return 0;}
//Usage.h#ifndef USAGE_H_INCLUDED#define USAGE_H_INCLUDED#include#include #include #include#include #include#include#include #include#include #include#include #include#include #include#include #include#include #include#include #include#include #includeusing namespace std;inline void err_quit(std::string message);inline void err_exit(std::string message);void usage(){cerr << "Usage:" << endl;cerr << "./semtool -c #create" << endl;cerr << "./semtool -d #delte" << endl;cerr << "./semtool -p #signal" << endl;cerr << "./semtool -v #wait" << endl;cerr << "./semtool -s #set-value" << endl;cerr << "./semtool -g #get-value" << endl;cerr << "./semtool -f #print-mode" << endl;cerr << "./semtool -m #set-mode" << endl; }int sem_create(key_t key){int semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);if (semid == -1)err_exit("sem_create error");return semid;}int sem_open(key_t key){int semid = semget(key, 0, 0);if (semid == -1)err_exit("sem_open error");return semid;}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; /* Buffer for IPC_INFO (Linux-specific) */};int sem_getmode(int semid){union semun su;// 注意: 下面這兩行語句一定要設(shè)定.// (告訴內(nèi)核使用的semun的哪個字段)struct semid_ds sd;su.buf = &sd;//if (semctl(semid, 0, IPC_STAT, su) == -1)err_exit("sem_getmode error");printf("current permissions is: %o\n", su.buf->sem_perm.mode);return 0;}int sem_setmode(int semid, char *mode){union semun su;// 注意: 下面這兩行語句一定要設(shè)定.// (告訴內(nèi)核使用的semun的哪個字段)struct semid_ds sd;su.buf = &sd;//sscanf(mode, "%o", (unsigned int *)&su.buf->sem_perm.mode);if (semctl(semid, 0, IPC_SET, su) == -1)err_exit("sem_setmode error");return 0;}int sem_getval(int semid){int value = semctl(semid, 0, GETVAL);if (value == -1)err_exit("sem_getval error");cout << "current value: " << value << endl;return value;}int sem_setval(int semid, int value){union semun su;su.val = value;if (semctl(semid, 0, SETVAL, su) == -1)err_exit("sem_setval error");return 0;}int sem_delete(int semid){if (semctl(semid, 0, IPC_RMID) == -1)err_exit("sem_delete error");return 0;}// 為了能夠打印信號量的持續(xù)變化, 因此sem_flg我們并沒用SEM_UNDO// 但是我們推薦使用SEM_UNDOint sem_P(int semid){struct sembuf sops = {0, -1, 0};if (semop(semid, &sops, 1) == -1)err_exit("sem_P error");return 0;}int sem_V(int semid){struct sembuf sops = {0, +1, 0};if (semop(semid, &sops, 1) == -1)err_exit("sem_V error");return 0;}inline void err_quit(std::string message){std::cerr << message << std::endl;exit(EXIT_FAILURE);}inline void err_exit(std::string message){perror(message.c_str());exit(EXIT_FAILURE);}#endif // USAGE_H_INCLUDED
附:ftok函數(shù)
系統(tǒng)建立IPC通訊(如消息隊列、共享內(nèi)存時)必須指定一個ID值。通常情況下,該id值通過ftok函數(shù)得到。
ftok原型如下:
key_t ftok( char * fname, int id )fname就時你指定的文件名(該文件必須是存在而且可以訪問的),id是子序號,雖然為int,但是只有8個比特被使用(0-255)。
返回值:
當成功執(zhí)行的時候,一個key_t值將會被返回,否則 -1 被返回。
在我們獲取到key之后,就可以使用該key作為某種方法的進程間通信的key值。