Linux系统编程POSIX有名信号量

追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Linux系统编程POSIX有名信号量相关的知识,希望能为你提供帮助。
00. 目录
文章目录

    • 00. 目录
    • 01. 概述
    • 02. 相关函数
      • 2.1 创建有名信号量
      • 2.2 关闭有名信号量
      • 2.3 删除有名信号量
      • 2.4 信号量P操作
      • 2.5 信号量V操作
    • 03. 程序示例
    • 04. 附录

01. 概述 在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥。它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。
02. 相关函数 2.1 创建有名信号量
#include < fcntl.h> /* For O_* constants */ #include < sys/stat.h> /* For mode constants */ #include < semaphore.h> sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); Link with -pthread. 功能: 创建一个有名信号量。 参数: name:信号量文件名。注意,不能指定路径名。因为有名信号量,默认放在/dev/shm 里 flags:sem_open() 函数的行为标志。 mode:文件权限(可读、可写、可执行)的设置。 value:信号量初始值。 返回值: 成功:信号量的地址 失败:SEM_FAILED

2.2 关闭有名信号量
#include < semaphore.h> int sem_close(sem_t *sem); Link with -pthread. 功能: 关闭有名信号量。 参数: sem:指向信号量的指针。 返回值: 成功:0 失败:-1

2.3 删除有名信号量
#include < semaphore.h> int sem_unlink(const char *name); 功能: 删除有名信号量的文件。 参数: name:有名信号量文件名。 返回值: 成功:0 失败:-1

2.4 信号量P操作
#include < semaphore.h> int sem_wait(sem_t *sem); 功能: 将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0, 此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。 参数: sem:信号量的地址。 返回值: 成功:0 失败: - 1int sem_trywait(sem_t *sem); ? 以非阻塞的方式来对信号量进行减 1 操作。 ? 若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); ? 限时尝试将信号量的值减 1 ? abs_timeout:绝对时间

abs_timeout补充说明
struct timespec { time_t tv_sec; /* seconds */ // 秒 longtv_nsec; /* nanosecondes*/ // 纳秒 }time_t cur = time(NULL); //获取当前时间。 struct timespec t; //定义timespec 结构体变量t t.tv_sec = cur + 1; // 定时1秒 sem_timedwait(& cond, & t);

2.5 信号量V操作
#include < semaphore.h> int sem_post(sem_t *sem); 功能: 将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。 参数: sem:信号量的地址。 返回值: 成功:0 失败:-1

03. 程序示例 示例一:有名信号量实现进程间互斥功能
#include< stdio.h> #include< semaphore.h> #include< fcntl.h> #include< unistd.h> #include< sys/stat.h> #include< sys/types.h> void printer(sem_t *sem, char *str) { sem_wait(sem); //信号量减一 while(*str!=\'\\0\') { putchar(*str); fflush(stdout); str++; sleep(1); } printf("\\n"); sem_post(sem); //信号量加一 } int main(int argc, char *argv[]) { pid_t pid; sem_t *sem = NULL; pid = fork(); //创建进程 if(pid< 0){ //出错 perror("fork error"); }else if(pid == 0){ //子进程 //跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量 sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1 if(sem == SEM_FAILED){ //有名信号量创建失败 perror("sem_open"); return -1; }char *str1 = "hello"; printer(sem, str1); //打印sem_close(sem); //关闭有名信号量_exit(1); }else if(pid > 0){ //父进程//跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量 sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1 if(sem == SEM_FAILED){//有名信号量创建失败 perror("sem_open"); return -1; }char *str2 = "world"; printer(sem, str2); //打印sem_close(sem); //关闭有名信号量wait(pid, NULL); //等待子进程结束 } sem_unlink("name_sem"); //删除有名信号量 return 0; }

测试结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out hello world deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

示例二: 有名信号量实现进程间同步功能(print2 先打印,再到 print1 打印)
【Linux系统编程POSIX有名信号量】print1.c 代码如下
#include < fcntl.h> /* For O_* constants */ #include < sys/stat.h> /* For mode constants */ #include < semaphore.h> #include < stdio.h> void print(sem_t *print1, sem_t *print2) { int i = 0; while(1) { sem_wait(print1); i++; printf("int print1 i = %d\\n", i); sem_post(print2); } } int main(int argc, char **argv) { sem_t *print1, *print2; print1 = sem_open("sem_print1", O_CREAT, 0777, 0); if(SEM_FAILED == print1) { perror("sem_open"); } print2 = sem_open("sem_print2", O_CREAT, 0777, 1); if(SEM_FAILED == print2) { perror("sem_open"); } print(print1, print2); return 0; }

print2.c 代码
#include < fcntl.h> /* For O_* constants */ #include < sys/stat.h> /* For mode constants */ #include < semaphore.h> #include < stdio.h> void print(sem_t *print1, sem_t *print2) { int i = 0; while(1) { sem_wait(print2); i++; printf("in print2 i = %d\\n", i); sleep(1); sem_post(print1); } } int main(int argc, char **argv) { sem_t *print1, *print2; print1 = sem_open("sem_print1", O_CREAT, 0777, 0); if(SEM_FAILED == print1) { perror("sem_open"); } print2 = sem_open("sem_print2", O_CREAT, 0777, 1); if(SEM_FAILED == print2) { perror("sem_open"); } print(print1, print2); return 0; }

删除有名信号量的代码:
#include < semaphore.h> #include < stdio.h> void sem_del(char *name) { int ret; ret = sem_unlink(name); if(ret < 0) { perror("sem_unlink"); } } int main(int argc, char **argv) { sem_del("sem_print1"); //删除信号量文件sem_print1 sem_del("sem_print2"); //删除信号量文件sem_print2 return 0; }

04. 附录

    推荐阅读