Linux环境编程进程间通信机制理解
一、Linux系统调用主要函数
一、Linux系统调用主要函数
首先,认识一下Linux下系统调用的主要函数,为后面进程与通信等做好铺垫。
以下是 Linux 系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的函数。
| fork | 创建一个新进程 |
| clone | 按指定条件创建子进程 |
| execve | 运行可执行文件 |
| exit | 中止进程 |
| _exit | 立即中止当前进程 |
| sleep(n) | 睡眠(等待/阻塞),n 为秒的单位 |
| getpid | 获取进程标识号 |
| getppid | 获取父进程标识号 |
| pause | 挂起进程,等待信号 |
| wait(参数) | 等待子进程终止 |
| waitpid | 等待指定子进程终止 |
| kill | 向进程或进程组发信号 |
| pipe | 创建管道 |
二、创建进程
接下来这部分相当于程序设计,通过系统调用创建进程,然后根据执行顺序进行判断,理解主进程和子进程的关系。
1、创建子进程系统调用fork()
#include <unistd.h>
#include <sys/types.h>
#include<stdio.h>
int main ()
{
pid_t pid; /* pid_t 是 short 类型 */
pid=fork();
if (pid < )
printf("error in fork!");
else if (pid == )
printf("i am the child process, my process id is %d\n",getpid());
else
printf("i am the parent process, my process id is %d\n",getpid());
return ;
}
这个程序很好理解:
fork()返回值0,进入子进程,返回值1,进入父进程,-1则是创建失败。

主要理解父子进程执行顺序是否与程序结构(判断语句前后)有关,所以再次进行以下测试,修改了判断语句顺序:
#include <unistd.h>
#include <sys/types.h>
#include<stdio.h>
int main ()
{
pid_t pid; /* pid_t 是 short 类型 */
pid=fork();
if (pid < )
printf("error in fork!");
else if (pid > )
printf("i am the parent process, my process id is %d\n",getpid());
else
printf("i am the child process, my process id is %d\n",getpid());
return ;
}
根据实验结果如图,对比之后发现运行结果相同,说明父子进程运行顺序与判断语句次序无关,始终是父进程优先执行。
2、验证fork()创建子进程效果
首先,我们再次对以上程序进行修改,第一次,测试打印语句放于fork()之前,观察结果:
#include <unistd.h>
#include <sys/types.h>
#include<stdio.h>
int main ()
{
pid_t pid; /* pid_t 是 short 类型 */
printf("see the print times\n");
pid=fork();
if (pid < )
printf("error in fork!");
else if (pid > )
printf("i am the parent process, my process id is %d\n",getpid());
else
printf("i am the child process, my process id is %d\n",getpid());
return ;
}

第二次,将打印测试放在fork()之后,结果:

由此可见得,在fork()创建子进程之后,有两个进程进行执行操作,所以执行了两次测试打印。
3、系统调用fork()与挂起系统调用wait()
实现代码如下:
#include <unistd.h>
#include <sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
int i, st;
pid_t pid1, pid2;
int sub_proc1(int id);
int sub_proc2(int id);
int main()
{
printf("\n\n\n");
if ((pid1 = fork()) == )
{
printf("The first child process id is %d\n", getpid());
sub_proc1();}
else
printf("i am the parent process id=%d \n",getpid());
if ((pid2 = fork()) == )
{
printf("The second child process id is %d\n", getpid());
sub_proc2();}
else
printf("i am the parent process id=%d \n",getpid());
i = wait(&st);
i = wait(&st);
printf("\n all finished!!!!!!!!!!!!!!!!!!\n");
exit();
return ;
}
int sub_proc1(int id)
{
printf("sub_proc%d is running !\n",id);
printf("sub_proc%d finish \n",id);
exit(id);
}
int sub_proc2(int id)
{
printf("sub_proc%d is running !\n",id);
printf("sub_proc%d finish \n",id);
exit(id);
}
解析:初始化创建了两个主进程,系统调用wait()更直观看出,程序先执行第一个主进程,再执行其子进程;然后执行第二个主进程,再执行其子进程。按照这个执行顺序,感知父子进程直接的关系,以及两个进程之间的执行顺序。证明结果:

三、模拟进程管道通信
我们知道,管道是进程之间的通信方法之一, 接下来通过进程的创建、管道的设置,实现进程间通过管道进行通信,然后认识在 Linux下进程间通过管道通信的编程。
原理:pipe() 把 p[ ] 与两个文件描述符紧密联系起来:
p[0] 用于从管道读
p[1]用于向管道写

使用到系统调用函数pipe() 和 fork()
#include <stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#define MSGSIZE 16
int pipe(int p[]);
char *msg1="hello, world #1";
char *msg2="hello, world #2";
char *msg3="hello, world #3";
int main()
{
char inbuf[MSGSIZE];
int p[], i, pid; if (pipe(p) < ) /* 打开管道 */
{
perror("pipe error!"); /* 无法打开一个管道错*/
exit();
}
if ( (pid = fork()) < )
{
perror("fork");
exit();
}
if (pid > ) /* 父进程 */
{
close(p[]); /* 关闭读端(连接) */
write(p[], msg1, MSGSIZE);
write(p[], msg2, MSGSIZE);
write(p[], msg3, MSGSIZE);
wait((int *));
}
if (pid == ) /* 子进程 */
{
close(p[]); /* 关闭写端 */
for (i=; i < ; i++)
{
read(p[], inbuf, MSGSIZE);
printf("%s\n", inbuf);
}
}
return ;
}
结果实现不同进行之间的通信,通过不同管道进行读写操作:

进程管道通信需要注意下面几个问题:
(1)关闭了一个方向

(2)管道的大小(Size)
每个管道都有一个大小限制,通常大约为 5k (5120) 个字节
(3)写问题:
write() 将被挂起(阻塞),如果管道中无法存放正文(容量不够),可能在写的过程中发生阻塞;
如果向一个没有读连接的管道写,将返回 -1, 且 errno 被置成 EPIPE。errno 是一个全局变量。
(4)读问题:
read() 将被阻塞,如果管道空,且有一个 写连接开放,read() 将返回 0 。
如果为空,且没有任何写连接,就此, 读进程可以知道通信结束。
四、pipe()下生产者与消费者问题
经典同步互斥问题,现在初始化有一个生产者,两个消费者,只有生产者有生产物资后,消费者才能使用,否则进入等待。

#include<sys/types.h>
#include<sys/file.h>
#include<string.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include <stdio.h>
char r_buf[]; //读缓冲
char w_buf[]; //写缓冲
int pipe_fd[];
pid_t pid1, pid2;
int producer(int id);
int consumer(int id);
int i,pid,status; /* status 用来表示进程退出的状态 */
int main()
{
if(pipe(pipe_fd)<)
{
printf("pipe create error \n");
exit(-);
}
else
{
printf("pipe is created successfully!\n");
if((pid1=fork())==)
producer();
if((pid2=fork())==)
consumer();
}
close(pipe_fd[]);//否则会有读者或者写者永远等待
close(pipe_fd[]);
for(i=;i<;i++)
pid=wait(&status); /* 等待子进程完成(取返回状态信息),主进程后
面未利用子进程的什么结果,直接在子进程完成后退出 */
exit();
}
int producer(int id)
{
int i;
printf("producer %d is running!\n",id);
close(pipe_fd[]);
for(i=;i<;i++)
{
sleep();
strcpy(w_buf,"aaa\0");
if(write(pipe_fd[],w_buf,)==-)
printf("write to pipe error\n");
}
close(pipe_fd[]);
printf("producer %d is over!\n",id);
exit(id);
}
int consumer(int id)
{
close(pipe_fd[]);
printf("consumer %d is running!\n",id);
strcpy(w_buf,"bbb\0");
while()
{
sleep();
strcpy(r_buf,"eee\0");
if(read(pipe_fd[],r_buf,)==)
break;
printf("consumer %d get %s, while the w_buf is %s\n",id,r_buf,w_buf);
}
close(pipe_fd[]);
printf("consumer %d is over!\n", id);
exit(id);
}
进程执行如下:

总结
学习之后的一篇总结,玩转Linux编程,更加深刻地去体验其中的原理,掌握基本的知识和操作。这篇记录总结学习,可以认识到程序与进程的区别,还有进程间通信机制,进程的执行顺序和关系。Linux系统调用函数的认识和使用更进一步掌握相关Linux知识。
另外,进程间的通信机制还有其他方法,进程信号中断通信内容,互斥同步问题,银行家算法等期待后续的学习总结记录,学习分享记录每一步,希望也能够帮助到有需要的朋友,大佬也多多指正!
我的CSDN博客:https://blog.csdn.net/Charzous/article/details/108287075
我的博客园:https://www.cnblogs.com/chenzhenhong/p/13580356.html
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Charzous/article/details/108287075
Linux环境编程进程间通信机制理解的更多相关文章
- Linux环境编程相关的文章
Linux环境编程相关的文章 好几年没有接触Linux环境下编程了,好多东西都有点生疏了.趁着现在有空打算把相关的一些技能重拾一下,顺手写一些相关的文章加深印象. 因为不是写书,也受到许多外部因素限制 ...
- linux系统编程--进程间通信
IPC方法 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问, 要交换数据必须通过内核,在内核中开 ...
- 读书笔记之Linux系统编程与深入理解Linux内核
前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...
- Linux网络编程--进程间通信(一)
进程间通信简介(摘自<Linux网络编程>p85) AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( s ...
- Linux 环境编程:dirfd参数 有关解析
背景 在Unix环境编程中,系统提供了很多以at结尾的函数,如openat.fstatat等,而这类函数通常有一个特点,就是形参列表中多了int dirfd 例如: int open(const ch ...
- 〖Linux〗Linux高级编程 - 进程间通信(Interprocess Communication)
[转自: http://blog.csdn.net/Paradise_for_why/article/details/5550619] 这一章就是著名的IPC,这个东西实际的作用和它的名字一样普及.例 ...
- Linux系统编程——进程间通信:管道(pipe)
管道的概述 管道也叫无名管道,它是是 UNIX 系统 IPC(进程间通信) 的最古老形式,全部的 UNIX 系统都支持这样的通信机制. 无名管道有例如以下特点: 1.半双工,数据在同一时刻仅仅能在一个 ...
- Linux系统编程——进程间通信:信号中断处理
什么是信号? 信号是 Linux 进程间通信的最古老的方式.信号是url=474nN303T2Oe2ehYZjkrggeXCaJPDSrmM5Unoh4TTuty4wSgS0nl4-vl43AGMFb ...
- Linux环境编程导引
计算机系统硬件组成 总线 贯穿整个系统的一组电子管道称为总线, 分为: 片内总线 系统总线 数据总线DB 地址总线AB 控制总线CB 外部总线 I/O设备 I/O设备是系统与外界联系的通道 键盘鼠标是 ...
随机推荐
- 第3章 探索性数据分析(单因子&对比)与可视化
1.理论铺垫 Dataframe和Series均适用 ~集中趋势:均值mean().中位数median().与分位数quantile(q=0.25).众数mode() ~离中趋势:标准差std().方 ...
- Python List cmp()方法
描述 cmp() 方法用于比较两个列表的元素.高佣联盟 www.cgewang.com 语法 cmp()方法语法: cmp(list1, list2) 参数 list1 -- 比较的列表. list2 ...
- PHP date_isodate_set() 函数
------------恢复内容开始------------ 实例 设置 2013 年第 5 周的 ISO 日期: <?php$date=date_create();date_isodate_s ...
- PHP parse_ini_file() 函数
定义和用法 parse_ini_file() 函数解析一个配置文件(ini 文件),并以数组的形式返回其中的设置. 语法 parse_ini_file(file,process_sections) 参 ...
- Skill 如何翻转一个list
https://www.cnblogs.com/yeungchie/ code 发现已经有内置了reverse(l_list) unless(fboundp('reverse) procedure(y ...
- luoguP2154 [SDOI2009]虔诚的墓主人
SDOI2009虔诚的墓主人 喜闻乐见,我终于把此题读懂了..所以可以写了. 其实就是让我们求有多少个十字架 一个十字架的定义为中间有一个空地 周围4个正方向都有k棵树. 不难想到nm的暴力 我们预处 ...
- Python代码规范性检测
一定要注重代码规范,按照平时的代码管理,可以将Python代码规范检测分为两种: 静态本地检测:可以借助静态检查工具,比如:Flake8,Pylint等,调研了一下,用Flake8的相对较多,功能满足 ...
- .Net Core下基于Emit的打造AOP
之前的基于DispatchProxy的AOP组件,实现了属性注入,但是这个依旧有很多限制 比如不支持构造器注入,继承DispatchProxy的子类必须是公开类 个人有点代码洁癖,不喜欢这种不能控制的 ...
- SqlServer 查询的几种方式以及数字函数、时间函数的应用总结(回归基础)
--语法:select * from 表名 *表示查询所有字段数据 select * from Class select * from Student select * from RankingLis ...
- JAVAWEB开发下常见中文乱码问题解决
JAVA环境下处理中文乱码问题一直是很多人困扰的问题,像URL传参乱码,写进数据库乱码,服务写中文文字图片乱码处理及导出PDF乱码. 1:安装中文支持 yum groupinstall "f ...
