今天继续研究进程相关的东东,话不多说,进入正题:

SIGCHLD:
关于它,之前章节的学习中已经用到了,具体可以参考博文:http://www.cnblogs.com/webor2006/p/3500972.html,这里会进一步来理解它:
 
说明:关于信号,很快就会有一个专题来仔细研究它,现在可以简单认为:它是一种异步通知事件
说明:如果父进程没有查询子进程的退出状态,子进程是没有办法真正完全退出的,这时子进程的状态就称为僵尸状态,该进程就叫僵尸进程
下面就对这两个函数进行详析:
wait:
 
下面用具体代码来进行说明:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>//提供wait函数声明

#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int main(int argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid == -)
ERR_EXIT("fork error"); if (pid == )
{
sleep();//子进程休眠,是为了看到父进程会等待子进程退出
printf("this is child\n");
exit();
} printf("this is parent\n");
int status;
wait(&status);等待子进程退出
return ;
}

看一下编译运行效果,下面用动画来展现,以便能体现到wait的意义:

从图中可以感受到,父进程虽然是已经输出了,但是一直是等到子进程退出了才退出,这也就是wait会让父进程去查子进程的退出状态,从而避免了僵尸进程的出现。

编译运行:

对于这些状态信息,可以通过调用系统宏来查询,下面具体来介绍下:

用来代码来解释:

编译运行:

下面我们可以用abort函数,来模拟子进程非法退出的情况:

这时再编译运行:

实际上,对于子进程非法退出的,还可以判断得再仔细一些,因为有好几种情况可以造成子进程非法退出,如上图所示,一是因为捕获信号而终止,二是被暂停了,具体用法如下:

编译运行:

关于信号,由于还没有学到,所以暂停的信号就不多说了,这里就不演示暂停信号的情况了,重在理解一下获取子进程退出状态信息的用法

【说明:上面的这些宏在sys/wait.h头文件里定义

waitpid:
对于上面刚学完的wait,它是等待随意的进程退出,因为一个父进程可以有多个子进程,如果只要有一个子进程退出,父进程的wait就会返回;
而waitpid则可以等待特定的进程退出,这是两者的区别,下面就来具体学习下这个函数的用法:
 
对于waitpid的pid参数的解释与其值有关:
实际上可以通过查看man帮助得到这个信息:
可以将我们之前的程序用waitpid替换一下,效果一样:
 
也同样,用它来改装我们之前的程序,对于父进程,实际上只有一个子进程,就可以直接传子进程的id既可,只等待这个子进程:
效果一样:
 
比如:waitpid(-100,&status,0)的意思就是,等待进程组ID=100里面的任一一个子进程。
 
最后,关于wait和waitpid,进行一个总结:
 另外,对于僵进程,已经被提到过好几次了,最后再来总结一下:

僵进程:
如何避免僵进程:
system:
 
实际上,它就等于用代码去执行我们在命令行中敲的那些shell命令,下面就以实际代码来认识这个函数的使用:
编译运行:
实际上,system()函数是调用"/bin/sh -c",如下:
对于这个函数的使用,其实没什么难的,但是这个函数很有代表性,我们可以通过它来综合运用我们所学习东西,这样其实还是挺有意义的,接下来,会自己实现一个跟system同样的功能,来达到理解system函数的实现原理:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int my_system(const char *command);//自己实现有system函数声明 int main(int argc, char *argv[])
{
my_system("ls -l | wc -w");//这里改用自己实现在system
return ;
} int my_system(const char *command)
{
pid_t pid;
int status;
if (command == NULL)
return ;
  if ((pid = fork()) < )
status = -;//出现不能执行system调用的其他错误时返回-1
  else if (pid == )
{//子进程
execl("/bin/sh", "sh", "-c", command, NULL);//替换成sh进程
exit();//如果无法启动shell运行命令,system将返回127,因为如果成功替换了之后,是不会执行到这句来的
    }
else
{//父进程会等到子进程执行完
while (waitpid(pid, &status, ) < )
{
if (errno == EINTR)//如果是被信号打断的,则重新waitpid
continue; status = -;
break;
}
     //这时就顺利执行完了
} return status;
}

编译运行:

可见,通过自己实现的system,就能够大致弄清楚它的原理,虽说程序比较少,但是五脏俱全,因为可以把自己学过的知识给运用起来。

好了,今天的学习就到这,下次见。

linux系统编程之进程(四)的更多相关文章

  1. linux系统编程之进程(一)

    今天起,开始学习linux系统编程中的另一个新的知识点----进程,在学习进程之前,有很多关于进程的概念需要了解,但是,概念是很枯燥的,也是让人很容易迷糊的,所以,先抛开这些抽象的概念,以实际编码来熟 ...

  2. linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid

    本节目标: 僵进程 SIGCHLD wait waitpid 一,僵尸进程 当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止. ...

  3. linux系统编程之进程(五)

    今天继续学习系统编程,学习的主题还是进程,今天主要讨论的是守护进程相关的概念,开始进入正题: 什么是守护进程:       守护进程的创建步骤: 在描述它之前,首先得先了解两个概念:进程组.会话期: ...

  4. linux系统编程之进程(二):进程生命周期与PCB(进程控制块)

    本节目标: 进程状态变迁 进程控制块 进程创建 进程撤消 终止进程的五种方法 一,进程状态变迁 进程的三种基本状态 就绪(Ready)状态 当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便 ...

  5. linux系统编程之进程(八):守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  6. Linux系统编程——Daemon进程

    目录 Daemon进程介绍 前提知识 Daemon进程的编程规则 Daemon进程介绍 Daemon运行在后台也称作"后台服务进程". 它是没有控制终端与之相连的进程.它独立与控制 ...

  7. linux系统编程之进程(三):进程复制fork,孤儿进程,僵尸进程

    本节目标: 复制进程映像 fork系统调用 孤儿进程.僵尸进程 写时复制 一,进程复制(或产生)      使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文.进程堆栈. ...

  8. linux系统编程--守护进程,会话,进程组,终端

    终端: 在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(Controlling Terminal), 进程中,控制终端是保存在PCB中的信息,而f ...

  9. Linux系统编程之进程概念

    注:本文部分图片来源于网络,如有侵权,请告知删除 1. 什么是进程? 在了解进程概念之前,我们需要先知道程序的概念. 程序,是指编译好的二进制文件,这些文件在磁盘上,并不占用系统资源. 进程,指的是一 ...

随机推荐

  1. [LeetCode] 240. Search a 2D Matrix II 搜索一个二维矩阵 II

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...

  2. VMware的包格式vmdk转换为virtualBox的ova

    使用winxp的vmdk作为案例 1 使用vmvare导入vmdk的winxp,点击文件---->导出为ovf 2 找到生成的ovf文件 3 打开virtualBox 管理---->导入虚 ...

  3. MySql 、Oracle 获取表结构和字段信息

    1.MySql获取表结构信息 SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.`TABLES` WHERE TABLE_SCHEMA ...

  4. Java开发笔记(一百三十八)JavaFX的箱子

    前面介绍了JavaFX标签控件的用法,其中提到Label文本支持中文字体,那么它到底支持哪些中文字体呢?自然要看当前的操作系统都安装了哪些字体才行,对于中文的Windows系统,默认安装了黑体“Sim ...

  5. typedefine 用法

    typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等). 用法: 变量别名 例如: 单个变量: t ...

  6. linux net通信 基于密钥

    配置SSHD服务 SSH(Secure Shell)是一种能够以安全的方式提供远程登录的协议,也是目前远程管理 Linux 系统的首选方式.在此之前,一般使用 FTP 或 Telnet 来进行远程登录 ...

  7. 数据分析-numpy的用法

    一.jupyter notebook 两种安装和启动的方式: 第一种方式: 命令行安装:pip install jupyter 启动:cmd 中输入 jupyter notebook 缺点:必须手动去 ...

  8. flask框架(三)——路由系统route转换成add_url_rule及源码分析

    这节我们不用@app.route来写路由,而是通过add_url_rule 传统写法  (<int:nid>传递int类型参数,endpoint是取别名) @app.route('/det ...

  9. 使用Kali MDK3无线攻击

    mdk3 <接口> <测试_模块> [测试选项] 例:mdk3 --wlan0mon b (通过mdk3 使用网卡接口调用b类测试模块发起攻击)请注意该mdk3软件在使用时必须 ...

  10. 我的Vue朝圣之路1

    1. Vue是什么? 1). 一位华裔前Google工程师开发的前端js库         2). 一个MVVM框架         3). 核心概念              * 数据绑定      ...