一、信号量
信号量有两种,一种的有名信号,一种是无名信号。有名信号一般用于进程间同步,无名信号一般用于于线程间同步。创建或打开一个信号的函数:
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag, ...);
name参数致命信号量的名字,由于信号量内部保存在系统内核中,多个进程间可以直接通过指定信号量的名字来相互通信。oflag表示信号的属性:可读、可写、可执行或者其他,如果指定了O_CREAT属性,则会创建信号量,否则表示打开已有信号量。后面的可选参数有两个:
mode
: 信号量的权限,和文件属性一样,0755或者其他。value
: 默认值,信号量内部维持了一个计数,value就是设置计数的默认值。
操作信号量的方法:
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);
wait表示等待一个信号量,当信号量中的计数不为0时,会把计数减1,然后继续执行后面的逻辑,如果计数为0,wait操作就会阻塞,直到计数不为0。trywait是wait的非阻塞版本,它会尝试wait,如果计数为0也直接返回。post操作会把计数加1,它和wait相对。只有通过它把计数加1后,阻塞的信号量才最继续往下执行。
关闭信号量:
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
close用于关闭信号量,这个操作会导致信号量的引用计数减1。当引用计数到达0后,执行过unlink的信号量会自动删除。
信号量的主要应用场景是同步,适合同步多个进程的状态同事到达某一个点。
二、示例代码
示例代码中创建了两个进程,每个进程都对一个变量执行三次自加操作。信号量的作用就是保证两个进程对变量自加操作的进度相同(意思是你自加了1次,我也自加1次,不存在你自加2次我才自加1次的情况)。
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#define SEMAPHORE_CHILD_NAME "sem_child"
#define SEMAPHORE_PARENT_NAME "sem_parent"
int main() {
int i, count;
sem_t *sem_child, *sem_parent;
pid_t pid;
// 创建两个信号量,用于父子进程间相互制约
sem_child = sem_open(SEMAPHORE_CHILD_NAME, O_RDWR | O_CREAT, 0755, 1);
sem_parent = sem_open(SEMAPHORE_PARENT_NAME, O_RDWR | O_CREAT, 0755, 1);
if (sem_child == NULL || sem_parent == NULL) {
perror("sem_open error");
return -1;
}
// 信号量使用完成后删除
sem_unlink(SEMAPHORE_CHILD_NAME);
sem_unlink(SEMAPHORE_PARENT_NAME);
pid = fork();
count = 0;
if (pid == 0) {
for (i = 0; i < 3; i++) {
// 等待父进程信号量
sem_wait(sem_parent);
count++;
// 设置子进程信号量
sem_post(sem_child);
printf("pid[%u]: count = %d\n", getpid(), count);
}
} else if (pid > 0) {
for (i = 0; i < 3; i++) {
// 等待子进程信号量
sem_wait(sem_child);
count++;
// 发送父进程信号量
sem_post(sem_parent);
printf("pid[%u]: count = %d\n", getpid(), count);
}
} else {
perror("fork error");
}
// 关闭信号量
sem_close(sem_parent);
sem_close(sem_child);
return 0;
}
执行结果:
可以看到,两个进程间的字节都是交替进行的。
此处评论已关闭