【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 */ // 秒long tv_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); //信号量值为 1if(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); //信号量值为 1if(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 打印)
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_print1sem_del("sem_print2"); //删除信号量文件sem_print2return 0;
}
04. 附录
【Linux系统编程】POSIX有名信号量相关推荐
- Linux系统编程:IPC信号量
文章内容 1. 信号量 2. 函数 2.1 命名信号量 / 基于文件 2.2 匿名信号量 / 基于内存 3. 读写锁 信号量:用于解决数据竞争,如同火车道上的信号灯,用来管理共享火车道(共享内存) 1 ...
- 【Linux系统编程学习】匿名管道pipe与有名管道fifo
此为牛客Linux C++和黑马Linux系统编程课程笔记. 0. 关于进程通信 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到 ...
- linux有名管道数据异常,Linux系统编程—有名管道
▋****1. 管道的概念 管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式. 1.1 管道本质 管道的本质也是一种文件,不过是伪文件,实际上是一块内核缓冲区, ...
- Linux——POSIX有名信号量
有名信号量 作用:主要用于同步线程或进程 头文件:#include <semaphore.h> 创建或打开信号量 /** 输入:const char* name ...
- 嵌入式Linux系统编程学习之二十五信号量
文章目录 前言 一.System V IPC 机制:信号量 1. semget 函数 2. semop 函数 3. semctl 函数 二.Posix 有名信号量 前言 信号量与信号量集的概念如下 ...
- 【Linux】一步一步学Linux系统编程教程汇总(暂时暂停更新......)
00. 目录 文章目录 00. 目录 01. 概述和标准 02. 文件操作 03. 进程概念 04. 进程间通信 05. 多线程 06. 信号 07. 同步与互斥 08. 高级IO 09. 其它 10 ...
- Linux系统编程 复习笔记
4 文件IO 操作 #include<fcntl.h> #include<unistd.h>#include<sys/types.h> creat int fd=c ...
- Linux系统编程笔记
文章目录 1.Linux系统编程 2.文件IO 2.1 文件描述符 2.2 open 2.3 perror 2.4 close 2.5 write 2.6 read 2.7 remove 2.8 系统 ...
- 【北京迅为iMX6ULL】嵌入式学习之Linux系统编程视频教程
什么是Linux系统编程? Linux系统编程也叫Linux下的高级编程,是介于应用层和驱动层之间的. 学习了哪些知识后可以学习Linux系统编程? C语言基础.Linux基本操作命令 怎么学习Lin ...
- 【读书笔记】linux系统编程
linux系统编程 原作名:Linux System Programming 作者: Robert Love 第一章 入门和基本概念 1.1 系统编程 应用程序需要与更高层次的库进行交互,系统程序就是 ...
最新文章
- Cause:compileSdkVersion is not specified
- 人脸识别引擎SeetaFaceEngine简介及在windows7 vs2013下的编译
- 华为畅享8的悬浮窗在哪里_华为畅享8悬浮球设置 | 手游网游页游攻略大全
- android view的隐藏和显示_Android使用Viewpager实现3D卡片翻动效果
- Linux(UOS) Qt不能播放音频的问题
- 【转载】Linux下有趣的命令
- 前端学习(1876)vue之电商管理系统电商系统之整体布局
- log4j2到oracle,Log4j2进阶使用(更多高级特性)
- Turtlebot3调试必看——爬坑笔记
- 工作方式 柔らかいコミュニケーション
- 施密特:乔布斯影响力还没有完全释放
- Juniper Junos DoS漏洞CVE-2017-2345 10.2及相关产品和平台均受影响
- 全国OA系统下载地址(全)
- 生命计算机在线,抖音死亡计算器寿命计算器在线测试入口 使用生命年龄计算器...
- 小水智能-智能楼宇智慧建筑3D可视化系统,实现了数据的整合
- python system interpreter_2. Using the Python Interpreter:使用Python解释器
- C#使用BouncyCastle来实现私钥加密,公钥解密的方法
- 用Burg法估计AR模型的参数原理详解及matlab实现
- C#项目启动会闪退问题解决
- [翻译] 在 Overleaf 中上传项目
热门文章
- easy ui 使用总结
- GIS数据格式整理之Coverage篇
- POJ 3349 Snowflake Snow Snowflakes
- html 在tomcat中访问不到_安全服务之安全基线及加固(四)Tomcat篇
- C语言字符串-字符串排序
- Java黑皮书课后题第4章:*4.26(金融应用:货币单位)重写程序清单2-10,解决将float型值转换为int型值时可能会造成精度损失的问题。读取的输入值是一个字符串,比如“11.56“
- C语言学习之输入10个数,输出其中最大的一个数。
- 启动日志_Hybris服务器启动日志分析
- luogu P2512 [HAOI2008]糖果传递
- Dropwizard入门及开发步骤