进程间通信(二)

共享内存

当进程A和进程B有一块共享的内存空间时,这两个进程之间的数据交互就会变的很简单,只需要像读取自己内存空间中的元素一样去读取数据即可。实现共享内存进行数据交互的一般步骤:

  1. 创建/打开共享内存
  2. 内存映射
  3. 数据交换
  4. 断开与共享内存的连接
  5. 清除共享内存

相关api

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>//创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int shmflg);
//连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
//断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(const void *shmaddr);
//控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

共享内存实现数据通信:
shmw.c:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(){int shmid;char *shmaddr;key_t key;key = ftok(".",1);shmid = shmget(key,1024*4,IPC_CREAT|0666);if(shmid == -1){printf("create share memory fail\n");}shmaddr = shmat(shmid,0,0);//第二个0是让系统自动分配空间,第三个0是默认可读可写printf("shmat ok!\n");strcpy(shmaddr,"hello world!");sleep(5);shmdt(shmaddr);shmctl(shmid,IPC_RMID,0);printf("quit!\n");return 0;
}

shmr.c:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(){int shmid;char *shmaddr;key_t key;key = ftok(".",1);shmid = shmget(key,1024*4,0);   //0代表正常获取共享内存if(shmid == -1){printf("create share memory fail\n");}shmaddr = shmat(shmid,0,0);//第二个0是让系统自动分配空间,第三个0是默认可读可写printf("read data from w:%s\n",shmaddr);shmdt(shmaddr);printf("quit!\n");return 0;
}

gcc shmw.c -o w;
gcc shmr.c -o r;
现在一个终端执行./w在另一个终端执行./r执行结果为为:
./w
shmat ok!
quit!
./r
read data from w:hello world!
quit!
另外我们可以利用ipcs -m指令查看当前系统中的共享内存。
共享内存也存在缺点,当进程A和进程B使用共享内存进行通信时,可能会出现这样一种情况:进程A和B同时向共享内存中写数据,可能会导致数据出现错乱。即共享内存不能实现原子操作,这种情况需要借助信号量来进行解决。

linux信号概述

对于linux来说,实际信号是软中断,许多重要的程序需要处理信号。信号,为linux提供了一种处理异步事件的方法。比如,终端用户输入了ctrl+c来终端程序,会通过信号机制停止一个程序。可以通过kill -l来查看系统中的信号

信号类型

kill -l1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

信号处理

对于信号我们可以采取三种方式来进行处理:忽略、捕捉和默认动作。

忽略信号

大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是SIGKILL和SIGSTOP)。

捕捉信号

可以写一个信号处理函数,然后把这个函数告诉内核,当该信号产生时,由内核来调用用户自定义的函数,一次来实现某种信号的处理。

系统默认动作

对于每个信号来说,系统都对应有默认的处理动作,当发生了该信号,系统会自动执行。

最简单的一个信号,当我们执行一个死循环时,我们可以直接利用kill -SIGKILL pid号来杀死该进程:

#include <stdio.h>
int main(){while(1);return 0;
}

运行这代断码会一直处理死循环,此时我们先利用 ps -aux|grep a.out来查看该进程的pid号,之后利用kill -9 pid或kill -SIGKILL pid来杀死该进程:
./a.out
Killed

信号变成

*#include <signal.h>
typedef void (sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

signum:就是选择上面的64种信号类型。handler是个函数指针,指明了遇到signum这种类型的信号将作何处理。
正常来说像我们上面的代码遇到while(1)卡死循环的情况我们可以用ctrl+C来终止进程,这是系统的默认动作,当然我们也可以捕捉信号,自己写一个handler函数来改变默认的行为:

#include <stdio.h>
#include <signal.h>void handler(int signum){printf("signum=%d\n",signum);printf("never quit!\n");
}int main(){signal(SIGINT,handler);while(1);return 0;
}

运行结果:
./a.out

^Csignum=2
never quit!
^Csignum=2
never quit!
^Csignum=2
never quit!
^Csignum=2
never quit!
^Csignum=2
never quit!

我们无法用ctrl+c来终止这个死循环进程。可以用kill -9 +pid来杀死进程。
同时我们也可以通过参数的方式利用代码来杀死进程:

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>int main(int argc,char **argv){int pid;int signum;signum = atoi(argv[1]);pid = atoi(argv[2]);printf("signum=%d,pid=%d\n",signum,pid);kill(pid,signum);printf("send signal ok!\n");return 0;
}

将这段代码编译为可执行程序,gcc signal1Ctl.c -o myKill;
首先运行./a.out就是上面那个死循环函数,直接在另一个终端查询该进程的pid号,然后运行./myKill 9 pid来杀死进程
在这里插入图片描述
除了利用kill来完成上述操作,我们也可以利用system来调用脚本:

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>int main(int argc,char *argv[]){int pid;int signum;char cmd[128];signum = atoi(argv[1]);pid = atoi(argv[2]);printf("signum=%d,pid=%d\n",signum,pid);//kill(pid,signum);sprintf(cmd,"kill -%d %d",signum,pid);//cmd="kill signum pid"system(cmd);printf("send signal ok!\n");return 0;
}

一样可以实现上述效果。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Markdown]是时候该学学使用markdown写文章了

&#x1f495;&#x1f495;&#x1f495;欢迎各位来到我的博客&#xff0c;今天我们的主题是markdown&#xff0c;你将在这里学习到最全的markdown知识&#x1f495;&#x1f495;&#x1f495; 你还在使用富文本编辑器写文档或文章吗&#xff1f; 你还在用word一点一点地进行…

LOTO示波器动作编程功能(命令批处理)

动作编程功能是为了方便客户根据自己的应用场景&#xff0c;做到一个按键就连续做多个示波器操作&#xff0c;从而降低了对操作人员的技术要求&#xff0c;做到傻瓜式操作。之前LOTO有个类似的功能&#xff0c;是把示波器的基础设置根据不同的测试场景存成不同的设置文件&#…

颍川诞生了两个帝王的仲父

伯、仲、叔、季是古代兄弟的长幼排行顺序&#xff0c;《释名释亲属》载&#xff1a;“父之弟曰仲父……仲父之弟曰叔父”。也就是古代称父亲的兄弟为仲父&#xff0c;多用于帝王对宰相重臣的尊称。 历史上最有名的、有正史记载的帝王“仲父”有两位&#xff0c;而且都出自颍川…

【Delphi 爬虫库 6】使用正则表达式提取猫眼电影排行榜top100

正则表达式库的简单介绍 正则表达式易于使用&#xff0c;功能强大&#xff0c;可用于复杂的搜索和替换以及基于模板的文本检查。这对于输入形式的用户输入验证特别有用-验证电子邮件地址等。您还可以从网页或文档中提取电话号码&#xff0c;邮政编码等&#xff0c;在日志文件中…

ROS2 工作空间

文章目录 ROS2 工作空间创建工作空间自动安装依赖编译工作空间设置环境变量参考链接 ROS2 工作空间 工作空间可以简单理解为工程目录。 ROS 系统中一个典型的工作空间结构如图所示&#xff1a; dev_ws&#xff1a; 根目录&#xff0c;里面会有四个子目录&#xff08;子空间&a…

Coursera吴恩达深度学习专项课程01: Neural Networks and Deep Learning 学习笔记 Week 03

Neural Networks and Deep Learning Course Certificate 本文是学习 https://www.coursera.org/learn/neural-networks-deep-learning 这门课的笔记 Course Intro 文章目录 Neural Networks and Deep LearningWeek 03: Shallow Neural NetworksLearning Objectives Neural Ne…

共享云桌面如何助力企业信息化和数字化?

随着科技的飞速发展&#xff0c;信息化和数字化已经成为企业转型的重要方向。共享云桌面作为一种新兴的信息化工具&#xff0c;正以其独特的优势助力企业实现信息化和数字化的目标。本文将详细探讨共享云桌面如何助力企业信息化和数字化的过程&#xff0c;以及它所带来的效益。…

词令蚂蚁新村今日答案:微信小程序怎么查看蚂蚁新村今天问题的正确答案?

微信小程序怎么查看蚂蚁新村今天问题的正确答案&#xff1f; 1、打开微信&#xff0c;点击搜索框&#xff1b; 2、打开搜索页面&#xff0c;选择小程序搜索&#xff1b; 3、在搜索框&#xff0c;输入词令搜索点击进入词令微信小程序&#xff1b; 4、打开词令微信小程序关键词口…

机器人系统ros2-开发实践08-了解如何使用 tf2 来访问坐标帧转换(Python)

tf2 库允许你在 ROS 节点中查询两个帧之间的转换。这个查询可以是阻塞的&#xff0c;也可以是非阻塞的&#xff0c;取决于你的需求。下面是一个基本的 Python 示例&#xff0c;展示如何在 ROS 节点中使用 tf2 查询帧转换。 本教程假设您已完成tf2 静态广播器教程 (Python)和tf…

数据结构十三:八大排序算法

排序算法&#xff08;sorting algorithm&#xff09;是用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。排序算法中的数据类型可以是整数、浮点数、字符或字符串等。排序的判断规则可根据需求设定&am…

SpringBoot内置插件的使用(jackson和lombok)

文章目录 引言I lombok(自动为属性生成构造器)II jacksonsee also引言 idea2021.2.2 已经捆绑安装jackson和lombok插件 I lombok(自动为属性生成构造器) Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。 https://p…

Leedcode题目:移除链表元素

题目&#xff1a; 这个题目就是要我们将我们的链表中的值是val的节点删除。 我们题目提供的接口是 传入了指向一个链表的第一个节点的指针&#xff0c;和我们要删除的元素的值val&#xff0c;不只要删除第一个&#xff0c; 思路 我们这里可以创建一个新的链表&#xff0c;…