POSIX 命名信号量
在前面已经介绍了 POSIX 匿名信号量的使用,POSIX 匿名信号量只能用于同一进程内的线程间通信,为了实现进程间的同步,可以使用 POSIX 命名信号量。
一个 POSIX 命名信号量必须要调用 sem_open 函数创建或打开之后才能使用。
当一个 POSIX 命名信号量使用完毕后,应该调用 sem_close 函数将其关闭;当一个 POSIX 命名信号量不再有任何用途时,应该调用 sem_unlink 函数删除它,SylixOS 会回收该信号量占用的内核资源。
命名信号量
命名信号量的创建与打开
#include <semaphore.h>
sem_t *sem_open(const char *name, int flag, ...);
函数 sem_open 原型分析:
- 此函数成功时返回一个 sem_t 类型的指针,失败时返回 NULL 并设置错误号。
- 参数 name 是 POSIX 命名信号量的名字。
- 参数 flag 是 POSIX 命名信号量的打开选项(O_CREAT,O_EXCL...)。
- 参数 … 是可变参数,通常可指定打开的模式(mode 和 value)。
如果需要创建一个 POSIX 命名信号量,打开选项应该加上 O_CREAT,并且可变参数应指定 mode 和 value 的值。
如果需要打开一个已经存在的 POSIX 命名信号量,打开选项不能够包含 O_CREAT 选项标志。
命名信号量的关闭
#include <semaphore.h>
int sem_close(sem_t *psem);
函数 sem_close 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 psem 是 POSIX 命名信号量的指针。
调用 sem_close 函数将减少一次命名信号量的使用计数,但不会删除一个命名信号量,需要注意的是,如果调用 sem_close 函数企图关闭一个匿名信号量,将返回-1 并设置 errno 为 EINVAL。
命名信号量的删除
#include <semaphore.h>
int sem_unlink(const char *name);
函数 sem_unlink 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 name 是 POSIX 命名信号量的名字。
sem_unlink 函数将删除一个不再使用的命名信号量,并释放系统资源。sem_unlink 函数会首先判断信号量的使用计数,如果使用计数到达了 0,则删除信号量,如果没有到达 0,则出错返回,并设置 errno 为 EBUSY。
下面程序通过命名信号量实现进程间的通信,服务器程序等待信号量 sem,当信号量解除等待后,代表命名管道中有新的数据可读,读数据完成后,服务器程序发送另一个信号量 sem1 给客户端表示读取数据完成。客户程序首先向管道中写入新的数据,然后发送信号量 sem 给服务器并等待信号量 sem1(服务器读操作完成)。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#define FIFO_NAME "/dev/fifo"
#define SEND_STR "server."
#define SEM_FILE "sem_named"
#define SEM_FILE1 "sem_named1"
int main (int argc, char *argv[])
{
int fd;
int i;
sem_t *sem, *sem1;
fd = open(FIFO_NAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open fifo error.\n");
return (-1);
}
sem = sem_open(SEM_FILE, 0);
if (sem == SEM_FAILED) {
fprintf(stderr, "sem_open error.\n");
return (-1);
}
sem1 = sem_open(SEM_FILE, 0);
if (sem1 == SEM_FAILED) {
fprintf(stderr, "sem_open error.\n");
return (-1);
}
for (i = 0; i < 10; i++) {
write(fd, SEND_STR, strlen(SEND_STR));
fprintf(stdout, "write \"%s\" to fifo.\n", SEND_STR);
sem_post(sem);
sem_wait(sem1);
}
close(fd);
sem_post(sem);
sem_close(sem);
sem_close(sem1);
return (0);
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#define FIFO_NAME "/dev/fifo"
#define SEND_STR "server."
#define SEM_FILE "sem_named"
#define SEM_FILE1 "sem_named1"
int main (int argc, char *argv[])
{
int ret, i;
int fd;
sem_t *sem, *sem1;
char buf[64] = {0};
ret = mkfifo(FIFO_NAME, 0777);
if (ret < 0) {
perror("mkfifo");
fprintf(stderr, "mkfifo error.\n");
return (-1);
}
fd = open(FIFO_NAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open fifo error.\n");
return (-1);
}
sem = sem_open(SEM_FILE, O_CREAT, 0644, 0);
if (sem == SEM_FAILED) {
fprintf(stderr, "sem_open error.\n");
return (-1);
}
sem1 = sem_open(SEM_FILE, O_CREAT, 0644, 0);
if (sem1 == SEM_FAILED) {
fprintf(stderr, "sem_open error.\n");
return (-1);
}
for (i = 0; i < 10; i++) {
sem_wait(sem);
read(fd, buf, strlen(SEND_STR));
fprintf(stdout, "read \"%s\" from fifo.\n", buf);
sem_post(sem1);
}
sem_wait(sem);
close(fd);
unlink(FIFO_NAME);
sem_close(sem);
sem_close(sem1);
sem_unlink(SEM_FILE);
sem_unlink(SEM_FILE1);
return (0);
}