IPC通信_信号量
信号量是一个计数器,用于为多个进程提供对共享数据的访问。
函数1
#include <sys/sem.h> int semget(key_t key, int nsems, int flag);
该函数转换键值获取信号量ID, key键值的获取还是通过ftok函数。
返回值 :成功返回信号量ID, 失败返回-1
参数key :键值(key)
参数nsems:初始信号量集合中的数组个数,如果是新建的必须指定该值,如果引用已有信号量,则置为0
参数flag :设置的权限,可参考消息队列。
函数2
#include <sys/sem.h> int semctl(int semid, int semnum, int cmd, .../*union semun arg*/);
该函数对信号量执行多种操作。其中第四个参数arg可选,是否使用取决于所请求的命令。
union semun
{
int val;
struct semid_ds *buf;
unsigned short* array;
}
参数semid :信号量ID
参数semnum:指定信号量集合中哪个成员,从0到nsems-1
参数cmd :见下表
cmd参数 |
释意 |
IPC_STAT |
参考消息队列 |
IPC_SET |
参考消息队列,第四个参数取联合中的arg.buf |
IPC_RMID |
参考消息队列 |
GETVAL |
返回成员semnum的semval值 |
SETVAL |
设置成员semnum的semval值,该值由arg.val指定 |
GETPID |
返回成员semnum的sempid值 |
GETNCNT |
返回成员semnum的semncnt值 |
GETZCNT |
返回成员semnum的semzcnt值 |
GETALL |
取该集合中所有的信号量值。这些值存储在arg.array指向的数组中 |
SETALL |
将该集合中所有的信号量值设置成arg.array指向的数值中的值 |
返回值: 除了GETALL以外的所有get命令,semctl函数都返回相应值。其他命令成功0,失败返回-1。
函数3
#include <sys/sem.h> int semop(int semid, struct sembuf semoparray[], size_t nops);
返回值:成功返回0,失败返回-1
参数semid:信号量ID
参数semoparray:一个指针,指向有sembuf结构表示的信号量操作数组
struct sembuf
{
unsigned short sem_num; //操作第几个信号量,0~nsems-1
short sem_op; //信号量要加减的数,可以是正数、负数、0
short sem_flg; //标志位IPC_NOWAIT, SEM_UNDO
}
参数nops:规定该数组中操作的数量
举例:
两个线程,一个线程通过信号量控制另一个信息打印
sem_1.cpp
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int set_semvalue(int sem_id, int count) {//用于初始化信号量,在使用信号量前必须这样做 union semun sem_union; sem_union.val = count; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) { printf("set_semvalue failed\n"); return -1; } return 0; } void del_semvalue(int sem_id) {//删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) { printf("del_semvalue failed\n"); } } int semaphore_p(int sem_id) {//对信号量做减1操作,即等待P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1;//P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_p failed\n"); return -1; } return 0; } int semaphore_v(int sem_id) {//这是一个释放操作,它使信号量变为可用,即发送信号V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1;//V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\n"); return -1; } return 0; } int main(int argc, char *argv[]) { key_t key = ftok("/tmp/",2); //创建信号量 int sem_id = semget(key, 1, 0666 | IPC_CREAT); set_semvalue(sem_id, 0); for(int i = 0; i < 10; ++i) { semaphore_p(sem_id); printf("sem1 print\n"); } printf("\n%d - finished\n", getpid()); del_semvalue(sem_id); return 0; }
sem_2.cpp
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int set_semvalue(int sem_id, int count) {//用于初始化信号量,在使用信号量前必须这样做 union semun sem_union; sem_union.val = count; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) { printf("set_semvalue failed\n"); return -1; } return 0; } void del_semvalue(int sem_id) {//删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) { printf("del_semvalue failed\n"); } } int semaphore_p(int sem_id) {//对信号量做减1操作,即等待P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1;//P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_p failed\n"); return -1; } return 0; } int semaphore_v(int sem_id) {//这是一个释放操作,它使信号量变为可用,即发送信号V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1;//V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { printf("semaphore_v failed\n"); return -1; } return 0; } int main(int argc, char *argv[]) { key_t key = ftok("/tmp/",2); //创建信号量 int sem_id = semget(key, 1, 0666 | IPC_CREAT); //set_semvalue(sem_id, 0); for(int i = 0; i < 10; ++i) { //semaphore_p(sem_id); printf("sem2 semaphore_v\n"); semaphore_v(sem_id); sleep(1); } printf("\n%d - finished\n", getpid()); //del_semvalue(sem_id); return 0; }