Linux间的进程通信;以及子进程的创建
"-----第六天-----------------------------------------------------------------------------" .版本控制:svn/git; .进程的概念:
)程序和进程;
每个进程操作系统会为它分配 -4G 的虚拟内存空间(32位操作系统); 其中0-3G为用户内存空间,进程可以对它进行读写操作; 3G - 4G 为系统内核空间,进程没有读写权限。
进程只能读写用户空间,没有权限读写内核空间(kernel);
)内存页面的概念
操作系统是按页来管理内存的;每个页有4096个字节。
还可以设置页面属性:如char *str = "hello",字符串在只读数据段,此时只能读,不能写。 )进程的4种形态:-3级; 级(内核态),最高; 3级(用户态);最低。 )并发:
)单道程序设计/多道程序设计
)CPU/MMU
)PCB:结构体;其中有一个指针指向文件描述符表;文件描述符表中存储1024个指针;已经打开的文件结构体。
每个进程有属于自己的PCB(进程的状态描述符);但是多个进程只有一个内核区。
.环境变量控制
)echo $名称; 查看该名称的环境变量。
)查看系统的环境变量: env;
)获取环境变量的值:char *getenv(const char* name); 获取键name环境变量的值。
)设置环境变量:int setenv(const char *name, const char *value, int rewrite); 将环境变量name的值设置为 value。
如果环境变量 name 已存在;则 rewrite 非0,覆盖原来的环境变量;rewrite为0,则不覆盖原来的环境变量。
)删除环境变量: void unsetenv(const char *name) 删除 name 的定义; )进程里可以设置自己的环境变量,避免设置在终端,影响他人。
.环境控制原语:
)fork:
)wait/waitpid
) . printenv.c .进程的状态: 种或 种,都对。 就绪, 运行, 睡眠, 停止。 .CPU的组成状态: 运算器,寄存器,控制器,译码器。 操作系统完成进程调度。(cpu进行时钟周期运算)
cpu的分时复用功能,使进程看起来像多进程。
在单核 cpu 上,同一时间只能有一个进程处于运行状态。那么多核 cpu,就可以有多个进程处于运行状态。 .进程原语:
)创建子进程。pid_t fork(); 调用1次,返回两次;在父进程返回子进程的 PID, 在子进程返回0.
) fork()的工作进程:先调用 creat(),创建一个进程, 在调用 clone(),给子进程复制父进程的内容;
)pid = fork(); //此时父子进程就都出来了。
)pid_t getpid(); 返回调用进程的PID号;
pid_t getppid(); 返回调用进程的父进程的PID号
当在子进程中 getpid(),得到的值与 fork()父进程的返回值相等,都是这个子进程的id号
)父子进程:读时共享,写时复制。
)最大创建进程 个数;
. uid_t getuid(void); //返回实际用户id;
uid_t geteuid(void); //返回有效用户id;
"注意: 文件实际用户与有效用户在创建该文件的家目录下时,如果没有修改,此时是相通的。
当文件被拷贝到root目录时, "
设置用户id; chmod ; 是设置用户ID。 完后效果为 -rwsr-xr-x; s表示设置了用户ID。
作用:当执行此文件时,执行者有效用户ID变为此文件的所有者。
设置用户组ID: chmod ; 是设置用户ID和组ID; 效果为: -rwsrwsrwx; . exec族函数的使用:
)功能: 去磁盘中加载另一个可执行程序,用它的代码段、数据段替换掉当前可执行程序的代码段、数据段;然后从后加载的这个程序退出,被替换的程序后续代码就不执行了。(换核不换壳,)
)一般情况下:与 fork() 函数联合使用;。 同时exec族函数不会创建新进程, 所以该程序的 ID 不会改变。 )函数的返回值: 成功没有返回值,运行完毕,自己退出。
失败返回 -;
)exec族函数的规律: l(list):命令行参数列表。 p(path): 搜索file时使用path变量。
v(vector):使用命令行参数数组。 e(environment):使用环境变量的数组,不使用进程原有的环境变量,设置新加载程序的环境变量; )int execl(const char *path, const char *argc, ...);
例如:execl("./bin/ls", "ls", "-l", "-a", NULL); 这几个参数的作用:其中第一个参数:"./bin/ls",命令的环境变量(即所在文件),不可以改变,必须完整正确;
"ls":占位参数,可以随便写,一般写成该命令。(不能缺失,如果缺失了,就会把后面的命令参数变为占位参数,输出结果会出错。) "-l","-a"该命令的参数。 NULL:卫兵,执行到这里时命令结束。 . toupper():将小写字母变为大写。 .僵尸进程,孤儿进程:
)S:睡眠状态; Z:僵尸状态;
)僵尸进程的产生原因:用户空间释放,内核空间的PCB没有释放,等着父进程回收。(它消耗的是内核当中的内存资源)
即:子进程退出,父进程没有回收子进程资源(PCB),则子进程变为僵尸进程。
)子进程的PCB(在内核空间)没有释放,是留给父进程回收用的。只有父进程回收后,僵尸进程才会消失。
)杀死僵尸进程的办法是杀掉它的父进程。 孤儿进程:父进程先于子进程结束,则子进程变为孤儿进程,子进程的变为1号进程init进程,由1号进程领养。 "僵尸进程比孤儿进程更危险, 因为它不会自动关;,而孤儿进程会由 1 号进程领养,当它执行完毕后,会被 1 号进程回收"。
做开发时主要避免的是僵尸进程的产生。用 wait(); waitpid(); 来避免僵尸进程的产生。 . pid_t wait(int* status); (阻塞函数,等待回收子进程资源;如果没有子进程,返回-);
)返回值:回收的子进程的ID号, wait(NULL);不关心子进程如何死亡,直接回收。
wait(&st); 用st来保存子进程死亡时的状态。 ) 父进程的ID与它的进程组ID相同;子进程的组ID与父进程的ID相同。
kill - -父进程的ID(即组进程的ID),这个进程组的所有进程都被杀死。"(注意 - 不能少)" .pid_t waitpid(pid_t pid, int *status, int options); (设置非阻塞。)
第一个参数 pid的值类型: ) < -; 回收指定进程组内的任意子进程。(因为父进程与子进程属于统一进程组,父进程与孙子进程属于不同的进程组,但是他们有血缘关系。)
-;回收任意子进程(只要有血缘关系就行。)
; 回收 当前调用 waitpid 一个进程组的所有子进程。
> ; 回收指定ID的子进程。
第二个参数:保存子进程的推出状态。 第三个参数:WNOHANG:如果没有子进程退出,立即返回。(实现了非阻塞的 wait). . 阻塞函数:非阻塞函数:在文件open(O_NONBLOCK)的时设置宏;读常规文件不会出现阻塞,当读伪文件时会出现。
例如:阻塞读终端; 管道; 网络; 设置非阻塞后:应设置轮询。 "=========进程间的通信(IPC)==========================================================================================================="
一。IPC方法:Linux环境下,多个进程间的通信,需要通过内核,在内核中开辟一块缓冲区(赋予他用户权限);进程1把数据从用户空间拷贝到内核缓冲区,
进程2 把数据从内核缓冲区拷读走,内核提供的这种机制称为进程间的通信(IPC)。 进程间的通信;四种方法:.pipe管道 .fifo有名管道,.内存共享映射 .Unix Domain Socket;
管道(使用最简单);信号(开销最小);共享映射区(速度最快,效率最高); 本地套接字(最稳定); 二。pipe管道:
.管道的特性:数据只能一个读,一个写,必须是一个方向。
半双工:数据同一时刻只能有一个流向。即只能父进程写,子进程读; 或子进程写, 父进程读。
全双工:数据同一时刻可以两个方向。
单工:数据只能同一个方向流动。
dup2(int oldfd, int newfd); 将第一个参数拷贝给第二个参数。
.其本质是一个伪文件(实为内核缓冲区)
.有两个文件描述符引用,一个读端,一个写端。
.规定数据从管道的写端流入,从读端流出。 管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区(4K)实现的。 管道的局限性:.数据不能自己写,自己读;
.管道中的数据不能反复读取,一旦读走,管道中不再存在。
.采用半双工通信方式,数据只能在单方向上流动。
.只能在有血缘关系之间的进程使用管道。
.只能进行单向通信,双向通信需要建立两个管道。 . pipe()创建管道,用于有血缘关系之间的通信。(采用环形队列实现的)
管道使用半双工通信; 创建完管道完后,确定通信方向:父写子读,或子写父读。
如果想创建多条管道,一定要先pipe(),再fork(),使子进程得以继承管道。 使用管道时的四种注意情况:
) 写段关闭,读端读完管道里的内容时;再次读,返回0,相当于读到文件末尾EOF;
)写端未关闭,写端无数据, 读端读完管道里的数据时,再次读,阻塞。
)读端关闭, 写段写管道,产生SIGPIPE信号,写进程默认情况下会终止进程。
)读端未读管道数据,当写段写满管道后,在此写,阻塞。
)使用管道,无须open,但需手动close。 管道的缓冲区大小:.函数的方法:fpathconf(int fd, int name); 第一个参数为管道描述符;第二个参数为情况标识符。
.命令: ulimit -a; . 总结:
.读管道:
.管道中有数据,read返回实际读到的字节数;
.管道中无数据,写端都被关闭,read返回 ,相当于读到文件末尾;
写端未关闭,read函数阻塞等待,(期待不久的将来会有数据到来,但此时会让出CPU资源)
.写管道:
.管道读端全部关闭;进程异常中止(返回一个终止信号);
.管道读端未关闭:
)管道已写满,write阻塞等待 )管道未写满,write将数据写入,返回实际写入的字节数; "==========================================================================="
.设置非阻塞管道的两种办法:
)fcntl函数设置非阻塞管道;
int flg = fcntl(fd, F_GETFD);
flg |= O_NONBLOCK;
fcntl(fd, F_SETFL, flg);
)打开文件时直接设置非阻塞;
int fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
当读取一个非阻塞文件,但是此时没有内容,会出错,错误码为EAGAIN;
. read() 函数的返回值四种情况;由于非阻塞设置的存在.
.返回值 > ; 读到的字节数
.返回值 < ; 读到文件末尾
.返回值 == -;但是errno != EAGAIN 或 EWOULDBLOCK
if( ret == -) {
if(errno == EAGAIN)
{
说明文件被设置为非阻塞方式读取,此时数据没有到达。
}
else
{
失败;
}
}
.返回值 == -, 但是errno == EAGAIN 或 EWOULDBLOCK;
说明此时文件被设置为非阻塞方式读取,数据还没有到达。
"========================================================================"
三. fifo有名管道:解决无血缘关系的进程通信;
.介绍:
FIFO文件在磁盘上没有数据块,仅仅用来标识内核中的一条管道。各进程可以打开这个文件进行read/write,实际上是在写内核通道,这样就实现了进程间的通信。
.创建fifo的方法:
)在终端创建一个有名管道;(不常用)用命令;"mkfifo 管道名";
)在代码运行时创建一个有名管道;(常用)用函数;int mkfifo(const char*pathname, mode_t mode);成功返回 ,失败-; .利用fifo实现非血缘关系进程间通信
.进程使用 “同一个fifo” 完成进程间通信。
.一个进程以只读方式打开read端,一个程序以只写打开写段。
.一根管道可以打开多个读端,多个写段。(一个写段多个读端; 或 一个读端多个写段); .多种特殊情况:
当一个写端多个读端时: 每个读端读取到的数据都不相同,因为从管道中读数据,读走之后,管道中的这个数据就不存在了;此时每个读端读到的所有内容合在一起为
管道写端写入的数据
当多个写端一个读端时, 每个写端写入的数据都会被这个读端读取出来;此时管道读到的数据为所有写端写入的数据。 四。mmap 内存映射: 从磁盘映射到kernel区,同时kernel区这段内存(映射占用的)开放了用户区的权限;所以进程可以进行访问 .文件是应用于进程间通信
)父子进程之间
可以用文件进行通信;
)非血缘关系进程间通信
可以用文件进行通信; .建立映射区,完成进程间通信
)mmap函数;六个参数的不同意义 )注意事项
.open的时候可以创建一个新文件,但是用此文件创建映射区时,大小不能为0;(可以进行文件拓展后再用来创建映射)
mmap使用的时候经常出现总线错误,通常是由于共享文件存储空间大小引起的。 .创建映射区的时候, 隐含着一次对文件的读操作;所以文件打开的方式只能为"读写;或读"。
当 MAP_SHARED(对内存的修改将反应到磁盘空间) 时,要求 映射区的权限 <= 文件打开的权限。
当 MAP_PRIVATE(对内存修改不会反应到磁盘空间) 时,此时则没有要求。(mmap中的权限是对内存的限制); .映射区创建完后关闭文件按描述符,对映射区没有影响。
."最后一个参数,偏移量必须是4K的整数倍。"
.munmap函数传入的地址一定要是mmap的返回地址。坚决杜绝对mmap函数的返回值进行++操作
.mmap创建映射区出错的概率非常高,必须进行出错判断。 )父子进程间的mmap(用户空间独立,内核去各进程共享。)
.先mmap创建映射区
.再fork()共享映射区内存首地址
.指定MAP_SHARED;(必须是 SHARED); )非血缘关系进程间通信
.使用“同一个文件”创建映射区
.两个进程,一个以read映射区,一个以write方式打开映射区;
.指定 MAP_SHARED;
)MAP_ANONYMOUS(匿名映射); 不可以用来通信
)/dev/zero(系统的伪文件); 不可以用来通信
)匿名映射
linux 创建匿名映射:第四个参数添加 MAP_ANON或MAP__ANONYMOUS;(注意这个匿名宏,只有Linux操作系统可以使用)。 UNIX(没有上述的匿名宏)。使用系统中的特殊文件(/dev/zero;(无限读,可以用来创建匿名映射)) .数据可以重复读取;(即多个读端读取一个写端,读取的内容相同,与fifo不同,取决于读取的数据)。 "====================进程间的通信(IPC)================================================================================================"
Linux间的进程通信;以及子进程的创建的更多相关文章
- Linux系统编程@进程通信(一)
进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...
- Linux程序设计:进程通信
日期:忘了. 关键词:Linux程序设计:System-V:进程通信:共享内存:消息队列. 一.共享内存 1.1 基本知识 (待补充) 1.2 代码 一个基于share memory实现的 ...
- linux 单机跨进程通信
一般来说通过网络通信(比如tcp,udp)或者共享内存的方式肯定可以实现跨进程通信,但现在这里要说的是比较偏但实用的几个方法:利用unix域通信(普通网络连接),利用unix域通信(socketpai ...
- linux下的进程通信之管道与FIFO
概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...
- 深入理解LInux内核-进程通信
进程间通信的基本机制:1.管道和FIFO(命名管道):最适合在进程之间实现生产者/消费者的交互.进程A向管道写入数据,进程B从管道读出数据.2.信号量:内核信号量的用户态版本.3.消息:允许进程在预定 ...
- linux下的进程通信之信号量semaphore
概念: IPC 信号量和内核信号量非常相似,是内核信号量的用户态版本. 优点:每个IPC信号量可以保护一个或者多个信号量值的集合,而不像内核信号量一样只有一个值,这意味着同一个IPC资源可以保护多个独 ...
- Linux学习笔记(13)-进程通信|命名管道
匿名管道只能在具有亲属关系的进程间通信,那么如果想要在不具有亲戚关系,想在陌生人之间通信,那又该怎么办呢? 别慌,Linux身为世界上*强大的操作系统,当然提供了这种机制,那便是命名管道-- 所谓命名 ...
- linux的IPC进程通信方式-匿名管道(一)
linux的IPC进程通信-匿名管道 什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号"|"来使用管道,但是管道的真正定义是 ...
- Android随笔之——跨进程通信(一) Activity篇
在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...
随机推荐
- MYSQL复习笔记10-连接
Date: 20140219Auth: Jin 一.介绍连接是二元运算,可以对两个表或多个表进行查询.T-SQL中分两大类,一是符合SQL标准的连接谓词表示形式,二是T-SQL扩展的使用关键字JOIN ...
- GCC 内联汇编(GCC内嵌ARM汇编规则)
转:http://smileleeboo.howbbs.com/posts/list/3127/81062.html 更多文档参见:http://pan.baidu.com/s/1eQ7nd8Q 有时 ...
- nodejs+mysql入门实例
此前我已准备好mysql,使用的是PHP的组合包Appserv 手动添加数据库依赖: 在package.json的dependencies中新增, “mysql” : “latest”, { &quo ...
- 如何优雅的编写Objective-C语言?
① 减少缩写 命名缩写只用于通用专业术语,如URL,不可自创命名缩写,如Ctr.Msg.命名宁可长一些,也不要难于理解. ② 过程化 动作发生之前用Will,发生之后用Did,询问是否发生用Shoul ...
- attribute用法
attribute 用法 摘要: 在学习linux内核代码及一些开源软件的源码(如:DirectFB),经常可以看到有关__attribute__的相关使用.本文结合自己的学习经历,较为详细的介绍了_ ...
- 流畅的python第十五章上下文管理器和else块学习记录
with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码, ...
- PHP100精华:很靠谱linux常用命令
vim是打开vim编辑器,别的编辑器还有vi(功能没有vim 强大),nano,emacs等等,感觉还是vim最强大,其次是vi,别的就要差一些了. 我听我们老师说,用图形界面本身已经会被高手笑了,如 ...
- PhantomJS + Selenium webdriver 总结-元素定位
webdriver提供了丰富的API,有多种定位策略:id,name,css选择器,xpath等,其中css选择器定位元素效率相比xpath要高些,使用id,name属性定位元素是最可靠,效率最高的一 ...
- python从数据库获取全量数据的方法
python从数据库获取全量数据的方法 学习了:https://blog.csdn.net/lom9357bye/article/details/79503658 原文膜拜: import psyco ...
- Mac OS X 10.10 执行 Eclipse 提示须要安装 Java