封装一个信号量集操作函数的工具
信號量的概念參見這里。
與消息隊列和共享內存一樣,信號量集也有自己的數(shù)據(jù)結構:
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 short ?sem_nsems; /* No. of semaphores in set */
};
同樣地,第一個條目也是共有的ipc 對象內核結構,剩下的是私有成員。
?Each semaphore in a semaphore set has the following associated values:
? ? ? ? ? ?unsigned short ?semval; ? /* semaphore value */
? ? ? ? ? ?unsigned short ?semzcnt; ?/* # waiting for zero */
? ? ? ? ? ?unsigned short ?semncnt; ?/* # waiting for increase */
? ? ? ? ? ?pid_t ? ? ? ? ? sempid; ? /* process that did last op */
即每一個在信號量集中的信號量都有上述4個相關的變量。
1、semval :當前某信號量的資源數(shù)目
2、semzcnt:當sem_op(見 struct sembuf)為0,且semop 函數(shù)沒有設置IPC_NOWAIT 標志,且當前semval 不為0,此時semzcnt 會加1,表示等待這個信號量的資源變?yōu)?的進程數(shù)加1,且進程會阻塞等待直到4個事件其中一個發(fā)生,具體可man 2 semop 一下。
3、semncnt:當sem_op(見 struct sembuf)< 0,且semop 函數(shù)沒有設置IPC_NOWAIT 標志,且當前semval < |sem_op| ,此時semncnt 會加1,表示等待這個信號量的資源增加的進程數(shù)加1,且進程會阻塞等待直到4個事件其中一個發(fā)生,具體可man 2 semop 一下。
4、當正確執(zhí)行了semop 函數(shù),則信號量集中的每個信號量的sempid 參數(shù)都被設置為改變此信號量的進程pid。
以下是幾個信號量集操作函數(shù):
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:用來創(chuàng)建和訪問一個信號量集
原型 int semget(key_t key, int nsems, int semflg);
參數(shù)
key: 信號量集的名字
nsems:信號量集中信號量的個數(shù)
semflg: 由九個權限標志構成,它們的用法和創(chuàng)建文件時使用的mode模式標志是一樣的
返回值:成功返回一個非負整數(shù),即該信號量集的標識碼;失敗返回-1
功能:用于控制信號量集
原型 int semctl(int semid, int semnum, int cmd, ...);
參數(shù)
semid:由semget返回的信號量集標識碼
semnum:信號量集中信號量的序號,從0開始編號
cmd:將要采取的動作(有三個可取值)
最后一個參數(shù)是 union semun,具體成員根據(jù)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) */
? ? ? ? ? ?};
返回值:成功返回0;失敗返回-1
cmd 取值如下:
SETVAL ?設置信號量集中的信號量的計數(shù)值
GETVAL ?獲取信號量集中的信號量的計數(shù)值
IPC_STAT 把semid_ds結構中的數(shù)據(jù)設置為信號量集的當前關聯(lián)值
IPC_SET 在進程有足夠權限的前提下,把信號量集的當前關聯(lián)值設置為semid_ds數(shù)據(jù)結構中給出的值
IPC_RMID 刪除信號量集
功能:用來創(chuàng)建和訪問一個信號量集
原型 int semop(int semid, struct sembuf *sops, unsigned nsops);
參數(shù)
semid:是該信號量集的標識碼,也就是semget函數(shù)的返回值
sops:是個指向一個結構體的指針
nsops:信號量的個數(shù)
返回值:成功返回0;失敗返回-1
struct sembuf
{?
unsigned short sem_num; ?/* semaphore number */
? ? ? ? ? ?short ? ? ? ? ?sem_op; ? /* semaphore operation */
? ? ? ? ? ?short ? ? ? ? ?sem_flg; ?/* operation flags */
};
sem_num:是信號量的編號。
sem_op:是信號量一次PV操作時加減的數(shù)值,一般只會用到兩個值,一個是“-1”,也就是P操作,等待信號量變得可用;另一個是“+1”,也就是我們的V操作,發(fā)出信號量已經(jīng)變得可用。當然+-n 和0 都是允許的。需要注意的是只有+n 才確保將semval +n 后馬上返回,而-n 和 0 很可能是會阻塞的,見文章上面的分析,+-n 需要進程對信號量集有寫的權限,而0 只需要讀的權限。
sem_flag:的兩個取值是IPC_NOWAIT或SEM_UNDO,設為前者如果當某個信號量的資源為0時進行P操作,此時不會阻塞等待,而是直接返回資源不可用的錯誤;設為后者,當退出進程時對信號量資源的操作撤銷;不關心時設置為0即可。
當要對一個信號量集中的多個信號量進行操作時,sops 是結構體數(shù)組的指針,此時nsops 不為1。此時對多個信號量的操作是作為一個單元原子操作,要么全部執(zhí)行,要么全部不執(zhí)行。
下面來封裝一個信號量集操作函數(shù)的工具:
semtool.c
?
C++ Code?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | ? | #include?<sys/types.h> #include?<unistd.h> #include?<sys/ipc.h> #include?<sys/sem.h> #include?<errno.h> #include?<stdio.h> #include?<stdlib.h> #define?ERR_EXIT(m)?\ ????????do?\ ????????{?\ ????????????????perror(m);?\ ????????????????exit(EXIT_FAILURE);?\ ????????}?while(0) union?semun { ????int?val;??????????????????/*?value?for?SETVAL?*/ ????struct?semid_ds?*buf;?????/*?buffer?for?IPC_STAT,?IPC_SET?*/ ????unsigned?short?*array;????/*?array?for?GETALL,?SETALL?*/ ????/*?Linux?specific?part:?*/ ????struct?seminfo?*__buf;????/*?buffer?for?IPC_INFO?*/ }; int?sem_create(key_t?key) { ????int?semid?=?semget(key,?1,?0666?|?IPC_CREAT?|?IPC_EXCL); ????if?(semid?==?-1) ????????ERR_EXIT("semget"); ????return?semid; } int?sem_open(key_t?key) { ????int?semid?=?semget(key,?0,?0); ????if?(semid?==?-1) ????????ERR_EXIT("semget"); ????return?semid; } int?sem_p(int?semid) { ????struct?sembuf?sb?=?{0,?-1,?/*IPC_NOWAIT*/SEM_UNDO}; ????int?ret?=?semop(semid,?&sb,?1); ????if?(ret?==?-1) ????????ERR_EXIT("semop"); ????return?ret; } int?sem_v(int?semid) { ????struct?sembuf?sb?=?{0,?1,?/*0*/SEM_UNDO}; ????int?ret?=?semop(semid,?&sb,?1); ????if?(ret?==?-1) ????????ERR_EXIT("semop"); ????return?ret; } int?sem_d(int?semid) { ????int?ret?=?semctl(semid,?0,?IPC_RMID,?0); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????return?ret; } int?sem_setval(int?semid,?int?val) { ????union?semun?su; ????su.val?=?val; ????int?ret?=?semctl(semid,?0,?SETVAL,?su); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????printf("value?updated...\n"); ????return?ret; } int?sem_getval(int?semid) { ????int?ret?=?semctl(semid,?0,?GETVAL,?0); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????printf("current?val?is?%d\n",?ret); ????return?ret; } int?sem_getmode(int?semid) { ????union?semun?su; ????struct?semid_ds?sem; ????su.buf?=?&sem; ????int?ret?=?semctl(semid,?0,?IPC_STAT,?su); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????printf("current?permissions?is?%o\n",?su.buf->sem_perm.mode); ????return?ret; } int?sem_setmode(int?semid,?char?*mode) { ????union?semun?su; ????struct?semid_ds?sem; ????su.buf?=?&sem; ????int?ret?=?semctl(semid,?0,?IPC_STAT,?su); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????printf("current?permissions?is?%o\n",?su.buf->sem_perm.mode); ????sscanf(mode,?"%o",?(unsigned?int?*)&su.buf->sem_perm.mode); ????ret?=?semctl(semid,?0,?IPC_SET,?su); ????if?(ret?==?-1) ????????ERR_EXIT("semctl"); ????printf("permissions?updated...\n"); ????return?ret; } void?usage(void) { ????fprintf(stderr,?"usage:\n"); ????fprintf(stderr,?"semtool?-c\n"); ????fprintf(stderr,?"semtool?-d\n"); ????fprintf(stderr,?"semtool?-p\n"); ????fprintf(stderr,?"semtool?-v\n"); ????fprintf(stderr,?"semtool?-s?<val>\n"); ????fprintf(stderr,?"semtool?-g\n"); ????fprintf(stderr,?"semtool?-f\n"); ????fprintf(stderr,?"semtool?-m?<mode>\n"); } int?main(int?argc,?char?*argv[]) { ????int?opt; ????opt?=?getopt(argc,?argv,?"cdpvs:gfm:"); ????if?(opt?==?'?') ????????exit(EXIT_FAILURE); ????if?(opt?==?-1) ????{ ????????usage(); ????????exit(EXIT_FAILURE); ????} ????key_t?key?=?ftok(".",?'s'); ????int?semid; ????switch?(opt) ????{ ????case?'c': ????????sem_create(key); ????????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?'d': ????????semid?=?sem_open(key); ????????sem_d(semid); ????????break; ????case?'s': ????????semid?=?sem_open(key); ????????sem_setval(semid,?atoi(optarg)); ????????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]); ????????break; ????} ????return?0; } |
首先來介紹一個getopt 函數(shù),?int getopt(int argc, char * const argv[],const char *optstring);
可以解析命令行選項參數(shù),前兩個參數(shù)由main 函數(shù)傳遞,第三個參數(shù)是一個字符串集,即解析命令行參數(shù)看是否存在這些字符。如./semtool -s 3 則s
為選項,3為選項參數(shù),optarg 是一個全局指針變量??extern char *optarg; ?通過atoi(optarg) 可以獲取數(shù)字3。
使用方法。
// optind: the index of first argument which has no option
// after getopt loop end: ./main -a xxx -b xxx ip port cnt ? ?optind points to ip
// usually optind+1 <= argc when no option arguments needed.
// argc: the count of arguments include exe; agrv[0 ~ argc-1]
key 已存在時返回錯誤,不再創(chuàng)建信號量集,而我們使用了ftok 函數(shù)產生一個唯一的key,傳入的參數(shù)一定,則每次產生的key 值
一樣,當?shù)诙未螆?zhí)行./semtool -c ,會返回file exist 的錯誤,當然先刪除當前信號量集,再create 是可以的,此時雖然key 還是一樣
的,但返回的semid 是不同的。
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s
------ Semaphore Arrays --------
key ? ? ? ?semid ? ? ?owner ? ? ?perms ? ? ?nsems ? ??
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool?
usage:
semtool -c
semtool -d
semtool -p
semtool -v
semtool -s <val>
semtool -g
semtool -f
semtool -m <mode>
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -c
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s
------ Semaphore Arrays --------
key ? ? ? ? semid ? ? ?owner ? ? ?perms ? ? ?nsems ? ??
0x730135db ?98304 ? ? ?simba ? ? ?666 ? ? ? ? ? 1 ? ? ? ??
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -v
current val is 1
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$?
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -v
current val is 1
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -s 3
value updated...
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -g
current val is 3
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -p
current val is 2
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -m 600
current permissions is 666
permissions updated...
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -d
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s
------ Semaphore Arrays --------
key ? ? ? ?semid ? ? ?owner ? ? ?perms ? ? ?nsems ? ??
可以設置信號量的資源數(shù)。ipcs -s 輸出中的nsems 表示信號量的個數(shù),當前只有一個;./semtool -v 輸出中的current value 表示這個信號量的資源數(shù)。
參考:《UNP》
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的封装一个信号量集操作函数的工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TensorFlow是什么?Tensor
- 下一篇: 紫书 习题8-14 UVa 1616(二