Unix环境——进程管理小结(一)

一、进程的基本概念

1、进程与程序

程序是存储在磁盘上的文件,它是包含要执行的机器指令和数据的静态实体。

进程是一个正在运行的程序,一个程序可能包含多个进程(多任务、多进程),进程在操作系统中是一个执行任务的单位。

2、进程的分类

交互进程:需要用户输入数据,也会显示一些结果给用户看。

批处理进程:用来执行脚本的进程,例如Makefil。

守护进程:它是一种一直活跃的进程,一般是后台的,由操作系统启动时通过开过开机脚本加载或由超级用户加载。

二、在linux下的一些关于进程的命令

ps:显示当用户当前终端所控制的进程。

-a:显示所有用户的进程

-x:包括无终端控制的进程

-u:显示详细信息

-w:以更宽的方式显示

ps aux   ps aux|grep pid(进程id)

三、进程信息表

USER:属主

PID:进程号

%CPU:cpu占用率

%MEM:内存使用率

VSZ:虚拟内存的大小

RSS:物理内存的使用量

TTY:终端设备号,如果不是终端控制进程用‘?‘表示。

STAT:终端的状态

START:开始时间

TIME:运行时间

COMMAND:开启此进程的命令

四、进程的状态

O:就绪态,一切准备工作都已经做好,等待被调用。

R:运行态,Linux下没有就绪态,O也就是R。

S:可唤醒的睡眠态,系统调用、获取到资源、收到信息都可以被唤醒。

D:不可唤醒的睡眠态,必须等到的事件发生。

T:暂停态,收到了SIGSTOP信号,当收到SIGCONT信号则继续运行。

X:死亡态。

Z:僵尸态。

<:高优先级。

N:低优先级。

L:多线程进程。

s:有子进程的进程。

+:后台进程组。

五、父子进程

如果进程B是由进程A开启的,那么我们把进程A叫进程B的父进程,进程B叫作进程A的子进程。

当子进程结束后会向父进程发送,SIGCHLD,父进程收到信号后再支回收子进程。

当先父进程先结束,子进程就会变成孤儿进程,会被孤儿院(init)收养。

如果子进程已经结束,但父进程没有及时回收,子进程就变成了僵尸进程。

六、进程的创建

1、fork函数

pid_t fork(void);

功能:创建子进程

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. int main ()
  4. {
  5. pid_t fpid; //fpid表示fork函数返回的值
  6. int count=0;
  7. fpid=fork();
  8. if (fpid < 0)
  9. printf("error in fork!");
  10. else if (fpid == 0) {
  11. printf("i am the child process, my process id is %d/n",getpid());
  12. printf("我是爹的儿子/n");//对某些人来说中文看着更直白。
  13. count++;
  14. }
  15. else {
  16. printf("i am the parent process, my process id is %d/n",getpid());
  17. printf("我是孩子他爹/n");
  18. count++;
  19. }
  20. printf("统计结果是: %d/n",count);
  21. return 0;
  22. }

运行结果是:

i am the child process, my process id is 5574

我是爹的儿子

统计结果是: 1

i am the parent process, my process id is 5573

我是孩子他爹

统计结果是: 1

在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,将要执行的下一条语句都是if(fpid<0)……

为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

1)在父进程中,fork返回新创建子进程的进程ID;

2)在子进程中,fork返回0;

3)如果出现错误,fork返回一个负值;

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

************

关于fork()的几点说明

1、失败返回-1,如果成功会返回两次。

2、父进程会返回子进程的id,子进程返回0

3、根据返回值的不同,分别为子进程和父进程设计不同的分支。

4、通过fork创建出的子进程,就是父进程的副本,它会把父进程的堆、栈、全局段、静态数据段、IO流的缓冲区都拷贝一份,父子进程共享代码段。

5、fork函数调用成功后,父子进程就开始各自执行了,它们的先后顺序是不确定的,但可以通过某些实现来保证。

2、vfork函数

pid_t vfork(void);

功能:创建子进程

1、vfork不能单独创建子进程,需要与excl函数簇,配合才完成子进程的创建。

2、它不会复制父进程的栈、堆、数据、全局等段,也不会共享代码段,而是通过excl函数调用一个程序直接启动,从面提高创建进程的效率。

3、使用vfork创建的子进程保证,先执行子进程,后执行父进程。

exec函数簇

exec函数的功能:加载一个可执行文件,要和vfork函数配合才有意义。

int execl(const char *path,  const  char

*arg, ...);

path:可执行文件的路径

arg:给可执行文件的参数,类似于命令行参数,必须以NULL结尾,第一个必须是可以执行文件名。

execl("","a.out",NULL);

int  execlp(const char *file, const char

*arg, ...);

file:可执行文件的文件名,会从PATH环境变量指定的位置去找可执行文件。

int execle(const char *path, const  char

*arg,..., char * const envp[]);

int  execv(const char *path, char *const

argv[]);

int execvp(const char *file, char *const

argv[]);

例子程序:

#include <stdio.h>

#include <unistd.h>

int main(int argc,char* argv[])

{

printf("我是进程%d\n",getpid());

for(int i=0; i<argc; i++)

{

printf("%s\n",argv[i]);

}

while(1)

{

sleep(1);

printf("hello world!\n");

}

}

#include <stdio.h>

#include <unistd.h>

int main()

{

int pid = vfork();

if(0 == pid)

{

printf("我是进程%d\n",getpid());

sleep(3);

execl("/home/zhizhen/hello","hello","haha","hehe","你好",NULL);

}

printf("我是%d的父进程%d\n",pid,getpid());

while(1)

{

printf("大家好,才是真的好!\n");

sleep(1);

}

}

说明:先有一个hello的程序创建出可执行文件hello 再在另一个程序中使用vfork

注意:

1、通过exec创建的子进程会替换掉父进程给的代码段,不拷贝父进程的堆、栈、全局、静态数据段,会用新的可执行文件替换掉他们。

2、exec只是加载一个可执行文件,并不创建进程,不会产生新的进程号。

3、只有exec函数执行结束(无论成功还是失败),父进程才能继续执行。

七、进程的正常退出

1、从main退出,在main中执行return 0;

返回值的低8位会被父进程获取到。

2、系统的_exit(stat)/标准的_Exit(stat),这两个函数几乎没有什么区别。

#include <unistd.h>

void _exit(int status);

#include <stdlib.h>

void _Exit(int status);

a、返回值的低8位会被父进程获取到。

b、使用_exit/_Exit退出前会关闭所有打开的文件流,如果有子进程则会托附给init,然后向父进程发送SIGCHLD信号。

c、此函数不会返回。

3、调用标准C的exit(stat)函数

a、exit在底层实现上调用了_exit/_Exit函数,所以_exit/_Exit的特点它都具备。

b、exit结束前会调用通过atexit/on_exit注册的函数。

int atexit(void (*function)(void));

int on_exit(void (*function)(int , void *), void *arg);

4、最后一个线程正常结束

八、进程异常中止

1、进程调用了abort函数(段错误、浮点异常)

2、进程接收到某些信号

crtl+c

crtl+\

ctrl+z

3、最后一个线程收到取消操作,而且线程作出响应。

九、子进程的回收

pid_t wait(int *status);

功能:等待子进程结束,并回收

pid_t waitpid(pid_t  pid,  int  *status,int options);

功能:等待指定的子进程结束,并回收

1、当一个进程结束时,内核会向它的父进程发送一个信号

父进程收到这个信号后可以指定一个函数来处理,也可以选择忽略,默认情况下是忽略的。

2、父进程调用wait调用才是有意义

如果所有的子进程都在运行,则父进程阻塞(wait)

只要有一个子进程结束了,会立即返回子进程的id和结束状态。

当所有子进程都结束运行时,wait会返回-1。

如果在调用wait之前子进程就已经结束(僵尸子进程),执行wait函数时会立即返回并回收僵尸进程。

3、waitpid函数可以指定等于哪个子进程

pid:指定的pid

== -1 功能与wait类似,pid就无意义了。

> 0 等待进程号是pid的进程结束。

== 0 等待组id等于pid的进程组中任意进程结束。

< -1 等待组id是pid的绝对值的进程组中任意进程结束。

status:用于接收子进程的结束状态,如果不需要状态码可以设置为NULL;

options:

0 以阻塞状态等待子进程结束

WNOHANG 如果没有子进程退出会立即返回。

WUNTRACED 等待的进程处于停止状态,并且之前没有报告过,则立即返回。

4、如果不调用wait/waitpid函数,子进程结束后就处于僵尸状态,当父进程也结束时,父进程的父进程会把他们统一回收。

最后关于僵尸进程和子进程的一些理解:

孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤

儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

  任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个
子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时
处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

原文地址:https://www.cnblogs.com/dachao0426/p/9362101.html

时间: 2024-08-29 18:23:55

Unix环境——进程管理小结(一)的相关文章

详谈 UNIX 环境进程异常退出

原文链接:http://www.ibm.com/developerworks/cn/aix/library/1206_xiejd_unixexception/ 详谈 UNIX 环境进程异常退出 本文详细论述 UNIX 环境上的进程异常退出,将导致进程异常退出的各种情景归纳为两类,对每类情况详细分析了问题出现的根本原因,同时添加了相应的实例以易于您更好地进行了解.在此基础上,文章最后论述了应该如何避免和调试进程异常退出问题.希望读者阅读此文后,对进程异常退出问题有更深层的认识,有更系统的梳理,对调

Linux crond任务调度 磁盘分区和挂载 网络环境 进程管理 服务(service)管理 动态监控进程 rpm和yum

crond任务调度 1.基本语法 1.crontab [选项] -e : bianji crontab定时任务 -l : 查询crontab -r : 删除当前用户所有的crontab任务2.编辑模式:时间格式 命令或脚本路径 参数说明 示例: 例子: 每分钟执行查看一次/ect目录,把目录内容写进/tml/a.txt下 具体实现步骤: 1.crontab -e 2.*/1 * * * * ls -l /etc >> /tmp/a.txt 3.保存退出 上述权限示例 Linux 磁盘分区.挂载

Linux性能及调优指南(翻译)之Linux进程管理

译文如下:1.1 Linux进程管理 进程管理是操作系统的最重要的功能之一.有效率的进程管理能保证一个程序平稳而高效地运行. Linux的进程管理与UNIX的进程管理相似.它包括进程调度.中断处理.信号.进程优先级.上下文切换.进程状态.进度内存等. 在本节中,我们将描述Linux进程管理的基本原理的实现.它将更好地帮助你理解Linux内核如何处理进程及其对系统性能的影响. 1.1.1 什么是进程?一个进程是一个运行在处理器的程序的一个实例.该进程使用Linux内核能够处理的任何资源来完成它的任

理解Docker容器的进程管理

摘要: Docker在进程管理上有一些特殊之处,如果不注意这些细节中的魔鬼就会带来一些隐患.另外Docker鼓励"一个容器一个进程(one process per container)"的方式.这种方式非常适合以单进程为主的微服务架构的应用.然而由于一些传统的应用是由若干紧耦合的多个进程构成的,这些进程难以 Docker在进程管理上有一些特殊之处,如果不注意这些细节中的魔鬼就会带来一些隐患.另外Docker鼓励"一个容器一个进程(one process per contain

UNIX环境C语言--进程管理、进程间通信

******进程管理******一.基本概念 1.进程与程序 进程就是运行中的程序,一个正在运行的程序可能包含多个进程,进程在操作系统中负责执行特定的任务 程序是存储在硬盘中的文件,它包含机器指令和数据,是一个静态的实体 进程或任务它是处理活动状态的计算机程序 2.进程的分类 a.交互进程:用户可以输入数据.也能看到程序的反馈信息 b.批处理进程:由系统命令各流程控制语句组成的可执行的脚本文件(Makefile) c.守护进程:一直活跃着的进程,一般在后台运行,由操作系统的开启脚本或超级用户加载

Unix下的进程管理

进程的概述 进程的概念 直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己的地址空间,有自己的堆,上级挂靠单位是操作系统.操作系统会以进程为单位,分配系统资源,所以我们也说,进程是资源分配的最小单位. 进程调度中的三种状态 运行:当一个进程在处理机上运行时,则称该进程处于运行状态.处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个.在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程. 就绪

(七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程

. . . . . 目录 (一) 一起学 Unix 环境高级编程(APUE) 之 标准IO (二) 一起学 Unix 环境高级编程(APUE) 之 文件 IO (三) 一起学 Unix 环境高级编程(APUE) 之 文件和目录 (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息 (五) 一起学 Unix 环境高级编程(APUE) 之 进程环境 (六) 一起学 Unix 环境高级编程(APUE) 之 进程控制 (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系

(六) 一起学 Unix 环境高级编程(APUE) 之 进程控制

. . . . . 目录 (一) 一起学 Unix 环境高级编程(APUE) 之 标准IO (二) 一起学 Unix 环境高级编程(APUE) 之 文件 IO (三) 一起学 Unix 环境高级编程(APUE) 之 文件和目录 (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息 (五) 一起学 Unix 环境高级编程(APUE) 之 进程环境 (六) 一起学 Unix 环境高级编程(APUE) 之 进程控制 上一篇博文中我们讨论了进程环境,相信大家对进程已经有了初步的认识

Supervisor安装与配置(Linux/Unix进程管理工具)

http://blog.csdn.net/xyang81/article/details/51555473 https://www.liaoxuefeng.com/article/0013738926914703df5e93589a14c19807f0e285194fe84000 1,Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统.它可以很方便