semget
int semget(key_t key, int nsems, int semflg); /** 示例1: 封裝一個創建一個信號量集函數 該信號量集包含1個信號量;**/ 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(信號量數量)可以填0,
**/ 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內核為System V信號量維護的數據結構 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 */ };
**/ 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: 獲取信號量集中第一個信號所關聯的值(GETVAL)
**/ 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[忽略第二個參數]. **/ 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); //創建一個信號量集 sem_setval(semid, 500); //設置值 cout << sem_getval(semid) << endl; //獲取值 sleep(10); sem_delete(semid); //刪除該集合 } /**
**/ int sem_getmode(int semid) { union semun su; // 注意: 下面這兩行語句一定要設定. // (告訴內核使用的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; // 注意: 下面這兩行語句一定要設定. // (告訴內核使用的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結構體 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的第三個參數設置為IPC_NOWAIT/0, 以查看程序的狀態的變化 **/ 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; }
下面我們封裝一個信號量操作函數工具,將主要的操作封裝起來,可以像命令一樣使用。
**/ //semtool.cpp #include "Usage.h" int main(int argc,char *argv[]) { int opt = 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 #include using 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; // 注意: 下面這兩行語句一定要設定. // (告訴內核使用的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; // 注意: 下面這兩行語句一定要設定. // (告訴內核使用的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; } // 為了能夠打印信號量的持續變化, 因此sem_flg我們並沒用SEM_UNDO // 但是我們推薦使用SEM_UNDO int 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函數
系統建立IPC通訊(如消息隊列、共享內存時)必須指定一個ID值。通常情況下,該id值通過ftok函數得到。
ftok原型如下:
key_t ftok( char * fname, int id )fname就時你指定的文件名(該文件必須是存在而且可以訪問的),id是子序號,雖然為int,但是只有8個比特被使用(0-255)。
當成功執行的時候,一個key_t值將會被返回,否則 -1 被返回。
在我們獲取到key之後,就可以使用該key作為某種方法的進程間通信的key值。