什么是进程
程序的运行实例,就是“进程”
一个程序,同时执行多次,则产生多个不同的进程。程序是静态的
进程是动态的进程的结构
进程的组成:程序代码、数据、变量、文件描述符(表示已打开的文件)、环境等组成。每个进程有一个唯一的编号,称为”进程标识符”(PID)
PID >= 2
PID=1的进程是init进程。进程之间共享程序代码
即,同一个程序的多个进程,共享一个代码拷贝。进程之间共享函数库。
进程有自己的”栈空间”、“程序计数器”、变量。
进程表
Linux把所有进程的相关信息放在一个表中,称为进程表
每个进程是一个表项。
进程表的索引,是PID可同时运行的进程数取决于该进程表的容量。
进程的查看
ps 显示与该终端连接的进程。
ps -ef
ps ax进程的状态
ps ax
ps的stat列表示进程的状态:
S: 睡眠,即“挂起”,等待某个事件的发生。
R: 运行
D: 不可中断的睡眠
T: 停止
Z: 死进程(僵尸进程)
s: 进程是会话期的首进程。
+:进程属于前台进程进程的调度
单处理器上,同一个时刻只能有一个进程运行。
Linux内核用“进程调度器”来决定下一个时间片执行哪个进程。进程的启动
1)system
实例:main7.c在程序的内部,创建一个新进程,执行指定的shell命令。 主进程将等待新进程执行结束后,才能继续执行。 除非新进程以后台方式运行,system("ls &") 效率不高,因为要先启动shell, 然后再运行指定的shell命令。
2) exec (进程替换)
exec指一组函数.
用于:从当前进程切换到另一个程序执行,且不返回到原来的程序(除非发生了错误,返回-1)。"l"组 (l即list, 新程序的参数为列表形式,即可变参数列表) execl execlp execle “v"组(v即vector, 新程序的参数为数组形式, 参数个数不变 execv execvp execve p后缀: 第一个参数是要执行的文件名,不含路径。 文件的路径由系统默认的环境变量(path)指定。 e后缀: 最后一个参数是字符串数组,表示指定的环境变量。 注意,这个环境变量是指程序替换以后, 新程序运行期间的环境变量。 而不是替换新程序时的环境变量, 所以execle函数的第一个参数仍然需要使用路径。 替换到新程序以后,此时的环境就是execle的最后一个参数。 实例:main8.c 分别用以上六种形式,创建"ls -l"进程。 注意: exec启动的新进程继承原进程的很多特性: 比如,原进程中打开的文件描述符,在新进程中仍保持打开。
3) fork (进程复制)
复制的新进程(子进程),与原进程一模一样,
但有自己的数据空间、环境、文件描述符等。fork的返回值 在原进程(父进程)中,fork返回新进程(子进程)的PID 在新进程(子进程)中,fork返回0 fork失败,返回-1 失败原因:父进程能拥有的子进程数超出限制(CHILD_MAX) 进程表中的空间不足 虚拟内存不足
实例:main9.c
等待子进程结束
1) wait
功能:父进程等待任意它的任一个子进程结束
返回该结束子进程的PID
参数: 实参非空时,返回子进程的退出状态。
参见man 2 wait实例:main10.c
2) waitpid
功能:父进程等待指定的子进程。
参数:
详见man 2 waitpid
参数3常使用WNOHANG(不阻塞,立即返回)
实例:
waitpid(child_pid, (int*)0, WNOHANG);
如果子进程未结束、未终止,则返回0
已经子进程已结束, 则返回子进程的PID
如果失败, 返回-1僵尸进程
1) 什么是僵尸进程
僵死进程(死进程):是指该进程已经结束运行,但在进程表中还没有删除它的相关信息。2)僵死进程产生的原因
子进程比父进程先结束,(儿子比父亲先“死”)
但是又不能在进程表中删除子进程的表项,因为父进程调用wait时还需要这些信息。3)僵尸进程的“归宿”
子进程比父进程先结束后,成为僵尸进程。
直到父进程也结束,该僵尸进程才真正消亡(从进程表中删除其表项)如果父进程被异常终止,则该僵尸进程认init进程为“父进程”
init进程发现该僵尸子进程后,再把它清除。应该尽量避免产生僵尸进程。
僵尸进程虽不再运行,但仍占用系统的资源!main11.c
测试:gcc main11.c
./a.out &
ps /* 子进程结束后 */
你知道:
for (i=0; i<2; i++) {
fork();
}
一共创建了多少个进程?