Linux编程_进程
目录
ps命令
进程标识符
进程的产生
多进程小案例
进程的消亡和释放
ps命令
ps命令用来查看进程相关信息,相关知识这里有介绍 https://www.cnblogs.com/Xiaoxiaogroup/p/14117133.html
进程标识符
(1)ps命令显示的PID字段就是进程标识符。
(2)进程标识符的类型为pid_t,该类型占位一般是有符号的16位整型数,大概有3万多个进程号。
(3)进程标识号是顺次向下使用,即使之前被杀死的进程,其进程号也不再重复使用。
(4)获取当前进程的进程号,使用函数getpid()。
(5)获取当前进程的父进程进程号,使用函数getppid()。
进程的产生
在学习多进程时,fork函数一定要理解透彻,理解父进程和子进程的关系才更深刻。
fork函数原型,如下图。

在当前进程中,使用fork函数创建子进程。
fork函数的功能是复制[duplicating]一个新进程。这里对复制这个关键字要注意,复制意味着复制的进程和原来的进程一样,包括程序执行的位置也是一样。
但是也有一些区别,复制出来的进程和原来的进程之间的区别,如:fork的返回值不同,父子进程的pid不同,ppid也不同。
未决信号和文件锁不继承。资源利用量清0(父进程使用了大量资源,子进程清0)。
这里还要注意一个进程init进程,init进程是所有进程的祖先进程,其进程号为1。
这里通过几个程序来了解fork函数的使用。
fork函数的返回值,fork函数执行一次,返回两个结果。
如果创建成功,父进程中返回值为子进程的PID,子进程中返回值为0,父子进程返回的pid是不同的。
如果创建失败,父进程中返回值为-1,子进程不会被创建。
fork语句下面一定是分支语句,用来确定是父进程或子进程。

程序执行结果。Begin一定是被打印一次,End分别被父进程和子进程各打印一次。

这里需要强调,父进程和子进程谁先被调用取决于调度器的调度策略。
如果想要子进程先被调用,最简单的方法是使用sleep函数让父进程睡眠一会。
下面的运行结果是子进程先运行,将父进程睡眠了一会。

使用ps axf 可以查看进程之间的关系,进程之间的阶梯状关系。

当前shell创建了,process1进程,process1创建了子进程。
进程实例2,代码如下。

这里将fflush这行语句注释掉。
使用下面的方式执行。

可以看出Begin!该语句执行了2次。产生这个现象的根本原因是什么?
在fork之前,fflush(NULL)刷新所有成功打开的流。终端是标准的输出设备,标准的输出设备默认是行缓冲模式\n可以刷新缓冲区。文件默认是全缓冲模式\n并不代表刷新缓冲区,代表换行。
fork案例,筛选质数。
单进程实现计算30000000---30000200之间的质数个数。使用宏定义数据区间。

程序输出结果,可以看出计算的结果是顺序输出,结果是从小到大排列的。。

查看程序所用的时间。
time ./primer > /dev/null

现在将当前程序改为多进程进行处理。
程序代码,父进程的工作是产生200个整数,fork出200个子进程。fork出来的每一个子进程的任务是进行判断整数是否为质数。
这里要注意,在子进程将任务执行完成后,需要将子进程退出,否则子进程将会产生新的子进程。

程序的输出结果,此时程序输出的结果是无序的。
使用 time,测试程序的执行时间。time ./primer1 > /dev/null

接下来做的操作是让父进程先退出。此时子进程的状态为S,可中断的睡眠态,子进程的父进程为init。
子进程为僵死态,一个僵尸态占用的资源很少,就是一个结构体,但是此时一个资源(pid)被占用。
父进程创建子进程,父进程需要收尸子进程。如果父进程先结束,子进程还在执行,那么子进程马上变成了孤儿进程,被init接管,最后由init来收尸。
所以在编程中需要注意,谁申请,谁释放,谁打开,谁关闭的原则。

进程的消亡及释放资源。
进程回收主要涉及到wait和waitpid两个函数,等待进程的状态发生变化(wait for process to change state)。

wait函数需要的参数是一个整型的地址,这里是将子进程收尸的状态放入到一个变量中。
这里需要给其一个整型的地址空间。
返回值,成功返回终止的子进程的id号,失败返回-1。
这里的参数可以为NULL。整型值提供一些宏来给我们检测当前进程的退出状态.

WIFEXITED 如果当前进程是正常终止,宏返回值为真。有5条正常终止,3条异常终止。exit _exit进程正常退出。
WEXITSTATUS 进程正常退出的状态,返回进程正常退出的退出码,这个宏使用前提得保证进程正常退出,打印正常退出的状态码。
WIFSIGNALED 如果当前子进程是一个信号终止的,这个宏返回值为真。
WTERMSIG 这个宏可以打印打断进程的信号值。
以上都是使用宏对整型值的状态进行检测,很多宏都是嵌套使用的。
wait是没有指向的,没有指定收尸要收谁。
pid_t waitpid(pid_t pid, int *status, int options);
waitpid好用的地方是options,它会一直等。
WNOHANG 有了这个选项,将waitpid由阻塞变成了非阻塞。
一个进程正常运行时,你要收尸无法收,该进程正在使用资源。
waitpid的pid的值可以大于0,要收尸的子进程指定的。为0,收同组中任何的子进程。为-1,收任何一个子进程不是同组的也可以。<-1,进程组的任何一个进程。
wait一定是阻塞的,waitpid可以不阻塞。
将我们的程序添加一个wait操作。
交叉分配法实现子进程完成任务。创建三个子进程完成200个待计算数的任务。

程序执行结果。

posted on 2020-12-06 16:48 XiaoXiaoli 阅读(134) 评论(0) 收藏 举报
浙公网安备 33010602011771号