进程间通信3

4. POSIX信号量

POSIX 有名信号量

这种有名信号量的名字由类似“/somename”这样的字符串组成,注意前面有一个正 斜杠,这样的信号量其实是一个特殊的文件,创建成功之后将会被放置在系统的一个特殊的 虚拟文件系统/dev/shm 之中,不同的进程间只要约定好一个相同的名字,他们就可以通过 这种有名信号量来相互协调。

4.1 POSIX 有名信号量的一般使用步骤是:

1,使用 sem_open( )来创建或者打开一个有名信号量。

2,使用 sem_wait( )和 sem_post( )来分别进行 P 操作和 V 操作。

3,使用 sem_close( )来关闭他。

4,使用 sem_unlink( )来删除他,并释放系统资源。

不像 system-V 的信号量可以申请或者释放超过 1 个资源,对于 POSIX 信号量而言,每 次申请和释放的资源数都是 1 。其中调用sem_wait( )在资源为 0 时会导致阻塞,如果不想 阻塞等待,可以使用 sem_trywait( )来替代。

4.2 代码

posix_w.c

#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>

//POSIX信号量的使用
int main()
{
    //创建一个共享内存对象,创建大小为2字节的共享内存
    int shmid = shmget(ftok("/",3),2,IPC_CREAT | 0777);
    //映射
    char* p = shmat(shmid,NULL,0);

    //创建posix信号量,代表空间 初始化大小为1
    sem_t* space = sem_open("/myspace",O_CREAT,0777,1);

    //创建posix信号量,代表数据 初始化大小为0
    sem_t* data = sem_open("/mydata",O_CREAT,0777,0);

    char* msg = "0123456789";
    int i=0;
    while(1){

        sem_wait(space);//相当于p操作
        memcpy(p,msg+i,1);//内存复制函数
        sem_post(data);//相当于v操作

        i = (i+1)%10;//循环的关键
    }

    return 0;
}

posix_r.c

#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>

//POSIX信号量的使用
int main()
{
    //创建一个共享内存对象,创建大小为2字节的共享内存
    int shmid = shmget(ftok("/",3),2,IPC_CREAT | 0777);
    //映射
    char* p = shmat(shmid,NULL,0);
    //创建posix信号量,代表空间 初始化大小为1
    sem_t* space = sem_open("/myspace",O_CREAT,0777,1);
    //创建posix信号量,代表数据 初始化大小为0
    sem_t* data = sem_open("/mydata",O_CREAT,0777,0);

    int i=0;
    while(1){

        sem_wait(data);//相当于p操作
        fprintf(stderr,p);
        sem_post(space);//相当于v操作

        i = (i+1)%10;//循环的关键
    }

    return 0;
}

运行

因为posix涉及到别的库的使用

所以我们编译运行时使用

gcc posix_w.c -o pw -lpthread

gcc posix_r.c -o pr -lpthread

但是我们的代码还有个错误

如果我们运行完一次并且ctrl+c停止了(其实时发送了一个SIGINT的中断信号,中止了程序),再次运行就没有效果了,需要去到 cd /dev/shm中删除我们创建的posix信号量,然乎再运行才行

这个bug我们在信号中改进

5.  信号

kiil -l 查看信号

信号是一种比较特别的 IPC,大部分的信号是异步的,换句话讲:一般情况下,进程什 么时候会收到信号、收到什么信号是无法事先预料的 (除了某几个特殊的信号之外) ,信号 的到来就像你家门铃的响起一样,你不知道他什么时候会响。

可以看见,Linux 系统中有许多信号,其中前面 31 个信号都有一个特殊的名字,对应

一个特殊的事件,比如 1 号信号 SIGHUP (Signal Hang UP) ,表示每当系统中的一个控制 终端被关闭 (即挂断,hang up) 时,即会产生这个信号,有时会将他们称为非实时信号, 这些信号都是从 Unix 系统继承下来的,他们还有个名称叫“不可靠信号”

5.1 非实时信号特点(不可靠信号)

1,非实时信号不排队,信号的响应会相互嵌套。

2,如果目标进程没有及时响应非实时信号,那么随后到达的该信号将会被丢弃。 

3,每一个非实时信号都对应一个系统事件,当这个事件发生时,将产生这个信号。

4,如果进程的挂起信号中含有实时和非实时信号,那么进程优先响应实时信号并且会 从大到小依此响应,而非实时信号没有固定的次序。

5.2 可靠信号特点

后面的 31 个信号 (从 SIGRTMIN[34] 到 SIGRTMAX[64]) 是 Linux 系统新增的实时信

号,也被称为“可靠信号”,这些信号的特征是:

1,实时信号的响应次序按接收顺序排队,不嵌套。

2,即使相同的实时信号被同时发送多次,也不会被丢弃,而会依次挨个响应。 

3,实时信号没有特殊的系统事件与之对应。

5.3 不可靠信号对应的意思

1,“备注”中注明的事件发生时会产生相应的信号,但并不是说该信号的产生就一定 发生了这个事件。事实上,任何进程都可以使用函数 kill( )来产生任何信号。

2 ,信号 SIGKILL 和 SIGSTOP 是两个特殊的信号,他们不能被忽略、阻塞或捕捉只 能按缺省动作来响应。换句话说,除了这两个信号之外的其他信号,接收信号的目标进程按照如下顺序来做出反应:

A) 如果该信号被阻塞,那么将该信号挂起,不对其做任何处理,等到解除对其阻塞为止。否则进入 B。

B) 如果该信号被捕捉,那么进一步判断捕捉的类型: 

B1) 如果设置了响应函数,那么执行该响应函数。

B2) 如果设置为忽略,那么直接丢弃该信号。否则进入 C。

C) 执行该信号的缺省动作。

5.4 kill函数和signal函数

很多人对 kill( )抱有偏见,以为他就是要“杀死”某人,但这并非他的初衷,除非他发 送的是一个致命的信号,否则他只是“发送一个信号”的行为并不一定会致对方于死地。

可以在代码中使用kill函数

还可以在linux终端这样使用命令

kill -SIGSTOP 进程pid     这个意思就是停止某一个进程

kill -SIGCONT 进程id    继续某一个进程

还可以使用信号编号

kill -19 进程pid    这个意思就是停止某一个进程

kill -18 进程pid    继续某一个进程

这个函数一般是跟 kill( )配套使用的, 目标进程必须先使用 signal( )来为某个信号设置 一个响应函数,或者设置忽略某个信号,才能改变信号的缺省行为,这个过程称为“信号的 捕捉” 。注意,对一个信号的“捕捉”可以重复进行,signal( )函数将会返回前一次设置的 信号响应函数指针。对于所谓的信号响应函数的接口,规定必须是:void (*)(int);

5.5 捕获信号练习

buhuo_w.c

#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include<signal.h>

//POSIX信号量的使用 和捕获信号

sem_t* space = NULL;
sem_t* data = NULL;

//关闭和删除文件
void wakeng(){
    sem_close(space);
    sem_close(data);
    sem_unlink("/myspace");
    sem_unlink("/mydata");
}

int main()
{

    signal(SIGINT,wakeng);//捕获一个信号(这里我们捕获的是ctrl+c发送的SINGINT信号)

    //创建一个共享内存对象,创建大小为2字节的共享内存
    int shmid = shmget(ftok("/",3),2,IPC_CREAT | 0777);
    //映射
    char* p = shmat(shmid,NULL,0);

    //创建posix信号量,代表空间 初始化大小为1
    space = sem_open("/myspace",O_CREAT,0777,1);

    //创建posix信号量,代表数据 初始化大小为0
    data = sem_open("/mydata",O_CREAT,0777,0);

    char* msg = "0123456789";
    int i=0;
    while(1){

        sem_wait(space);//相当于p操作
        memcpy(p,msg+i,1);//内存复制函数
        sem_post(data);//相当于v操作

        i = (i+1)%10;//循环的关键
    }

    return 0;
}

buhuo_r.c

#include <stdio.h>
#include <fcntl.h>              
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>           
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include<signal.h>

//POSIX信号量的使用 和捕获信号
sem_t* space = NULL;
sem_t* data = NULL;

//关闭和删除文件
void wakeng(){
    sem_close(space);
    sem_close(data);
    sem_unlink("/myspace");
    sem_unlink("/mydata");
}

int main()
{

    signal(SIGINT,wakeng);//捕获一个信号(这里我们捕获的是ctrl+c发送的SINGINT信号)

    //创建一个共享内存对象,创建大小为2字节的共享内存
    int shmid = shmget(ftok("/",3),2,IPC_CREAT | 0777);
    //映射
    char* p = shmat(shmid,NULL,0);
    //创建posix信号量,代表空间 初始化大小为1
    space = sem_open("/myspace",O_CREAT,0777,1);
    //创建posix信号量,代表数据 初始化大小为0
    data = sem_open("/mydata",O_CREAT,0777,0);

    int i=0;
    while(1){

        sem_wait(data);//相当于p操作
        fprintf(stderr,p);
        sem_post(space);//相当于v操作

        i = (i+1)%10;//循环的关键
    }

    return 0;
}

编译运行

再次运行依然可以

6. 精灵进程

daemon.c

#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

//精灵进程
int main()
{
	pid_t a;
	int max_fd,i;
	/***************************************************
	1.忽略SIGHUP信号(关闭终端),防止进程被CTTY控制终端关闭
	*****************************************************/
	
	signal(SIGHUP,SIG_IGN);
	
	/***************************************************
	2.生成第一个子进程,确保能够正确产生新的会话期
	*****************************************************/	
	
	a = fork();
	if(a > 0)
	{
		exit(0);
	}
	
	/***************************************************
	3.调用seipid()函数,让第一个子进程产生新的没有控制终端的会话期
	*****************************************************/	
	
	setsid();
	
	/***************************************************
	4.生成第二个子进程,防止精灵进程打开终端文件创建控制终端
	*****************************************************/	
	
	a = fork();
	if(a > 0)
	{
		exit(0);
	}
	
	/***************************************************
	5.分离精灵进程的原生进程组,防止接收到任何控制进程组的信号
	*****************************************************/	
	
	setpgrp();
	
	/***************************************************
	6.关闭所有的文件描述符,释放资源
	*****************************************************/	
	
	max_fd = sysconf(_SC_OPEN_MAX);
	for(i = 0; i < max_fd; i++)
	{
		close(i);
	}
	
	/***************************************************
	7.文件权限掩码清零
	*****************************************************/
	
	umask(0);
	
	/***************************************************
	8.改变进程的工作路径,确保进程不会被卸载
	*****************************************************/
	
	chdir("/");
	
	/***************************************************
	9.精灵进程创建成功
	*****************************************************/
	//精灵进程要干的事
	
	pause();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/219008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

派对的最大快乐值

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 派对的最大快乐值 &#x1f48e;总结 派对的最大快乐值 题目 员工信息的定义如下&#xff1a; 公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公…

【Hydro】Python绘制降雨径流双Y轴成果图

目录 说明源代码说明 双y轴图像具有单y轴图像没有的对比效果,通常会用来绘制降雨径流成果图,在MATLAB中有plotyy函数可以实现,Python的实现方式没有MATLAB那样方便,不过实现效果却也不见得差。 Python中的matplotlib通常使用twinx来生成双Y轴,下图便是使用matplotlib绘制…

配置linux系统用户名高亮

Centos: export PS1\e[1m\e[32m\u\h\e[m:\e[34m\w\e[31m\e[1m\$\e[m Ubuntu: force_color_promptyes

Graphpad Prism10.1.0 安装教程 (含Win/Mac版)

GraphPad Prism GraphPad Prism是一款非常专业强大的科研医学生物数据处理绘图软件&#xff0c;它可以将科学图形、综合曲线拟合&#xff08;非线性回归&#xff09;、可理解的统计数据、数据组织结合在一起&#xff0c;除了最基本的数据统计分析外&#xff0c;还能自动生成统…

【Python】OpenCV库中常用函数详解和示例

在Python中&#xff0c;OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个广泛使用的图像和视频处理库。它包含许多用于图像处理和计算机视觉任务的函数。本文对一些常用的OpenCV函数及其详细解释和示例&#xff0c;以帮助大家理解和使用。 目录 cv2.…

小型图书管理系统

摘要 随着各图书馆的图书数量不断增多和图书馆规模的不断扩大&#xff0c;管理这些庞大的体系非常困难的&#xff0c;因为图书的情况是随时改变的&#xff0c;因此必需对图书进行动态的管理&#xff0c;而这对于一个管理人员来说是一件比较复杂的事情。 针对各个模块不同的数据…

ros2+UBUNTU读取STM32发送过来的数据(C++)

ATTENTION:一般ros2上位机访问STM32不是使用串口&#xff0c;即使树莓派有串口&#xff0c;我也不会用的&#xff0c;因为那还要去学习其他的语言&#xff0c;一般就是ros2---------ubs转串口-------STM32串口。 这个USB转串口&#xff0c;我们已经安装了CH340驱动了&#xff…

Qt篇——QChartView实现鼠标滚轮缩放、鼠标拖拽平移、鼠标双击重置缩放平移、曲线点击显示坐标

话不多说。 第一步&#xff1a;自定义QChartView&#xff0c;直接搬 FirtCurveChartView.h #ifndef FITCURVECHARTVIEW_H #define FITCURVECHARTVIEW_H #include <QtCharts>class FitCurveChartView : public QChartView {Q_OBJECTpublic:FitCurveChartView(QWidget *…

23、什么是卷积的 Feature Map?

这一节介绍一个概念&#xff0c;什么是卷积的 Feature Map&#xff1f; Feature Map, 中文称为特征图&#xff0c;卷积的 Feature Map 指的是在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;通过卷积这一操作从输入图像中提取的特征图。 上一节用示意动图介绍了卷积算…

【开源】基于Vue和SpringBoot的开放实验室管理系统

项目编号&#xff1a; S 013 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S013&#xff0c;文末获取源码。} 项目编号&#xff1a;S013&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

3.镜像加速器

目录 1 阿里云 2 网易云 从网络上拉取镜像的时候使用默认的源可能会慢&#xff0c;用国内的源会快一些 1 阿里云 访问 阿里云-计算&#xff0c;为了无法计算的价值 然后登录&#xff0c;登录后搜索 容器镜像服务 点击容器镜像服务 点击管理控制台 点击 镜像工具->镜像…

Python的requests库实现HTTPS

嘿&#xff0c;Python程序员们&#xff01;今天我们要来点刺激的——使用Python的requests库实现HTTPS请求&#xff01;是的&#xff0c;你没有听错&#xff0c;我们要一起迈入HTTPS的神秘世界&#xff01; 首先&#xff0c;我们来了解一下HTTPS是什么。HTTPS是HTTP Secure的缩…

前端时间的失败总结复盘

分享失败经验&#xff0c;前段时间的总结复盘&#xff1a; 与伙伴合作面对异常决策要及时提出质疑&#xff0c;怼&#xff0c;别太客气&#xff0c;客气起来&#xff0c;小心翼翼在意他人情绪那么这个项目就会让人难受&#xff0c;不要因为因为伙伴身上有标签/光环/权威就觉得…

【C++】map和set的使用及注意事项

map和set的使用及注意事项 1.关联式容器2. 键值对3.set3.1接口介绍3.1.1构造3.1.2迭代器3.1.3容量3.1.4修改 3.2set使用及注意事项 4.multiset5.map6.multimap349. 两个数组的交集 1.关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xf…

持续集成交付CICD:Sonarqube 扫描本地项目(关联Gitlab项目与Jenkins流水线)

目录 一、实验 1.Java项目扫描 2.视图徽章 3.版本管理 一、实验 1.Java项目扫描 &#xff08;1&#xff09;指定项目信息关联的首页为GitLab项目&#xff0c;持续集成为Jenkins流水线 &#xff08;2&#xff09;命令行 sonar-scanner -Dsonar.host.urlhttp://192.168.20…

RAG落地实践、AI游戏开发、上海·深圳·广州线下工坊启动!星河社区重磅周

飞桨星河社区在成立的5年以来&#xff0c;已汇集660万AI开发者&#xff0c;覆盖深度学习初学者、在职开发者、企业开发者、高校教师、创业者等&#xff0c;已成为AI领域最具影响力的社区之一&#xff0c;无论是AI爱好者还是AI开发者&#xff0c;都能在这里探索AI的无限可能。 飞…

字符指针变量数组指针变量

字符指针变量 在指针的类型中&#xff0c;我们知道有一种指针叫做字符指针 一般的使用情况如下&#xff1a; #include<stdio.h> int main() {char ch w;char* pa &ch;*pa h;printf("%c", *pa);return 0; } 还有一种使用方法如下&#xff1a; #incl…

计算机速成课Crash Course - 07. 中央处理器

今天开始计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 07. 中央处理器 07. 中央处理器 提示下&#xff0c;这集可能是最难的一…

Python-图片去重

直接上代码 # 修改一下第34行文件夹路径以及13行图片后缀名即可使用 import os from hashlib import md5def remove_duplicate_images(folder_path):image_files []duplicate_images set()# 遍历文件夹&#xff0c;找到所有 JPG 图片文件for root, dirs, files in os.walk(f…

LeetCode | 110. 平衡二叉树

LeetCode | 110. 平衡二叉树 OJ链接 首先计算出二叉树的高度然后计算当前节点的左右子树的高度&#xff0c;然后判断当前节点的左右子树高度差是否超过 1&#xff0c;最后递归地检查左右子树是否也是平衡的。 //计算二叉树的高度 int height(struct TreeNode* root) {if(root…