目录
一,进程创建
写时拷贝
二,进程终止
三,进程等待
获取子进程status
一,进程创建
- 命令行启动命令(程序、指令等);
- 通过程序自身fork创建;
#include<unistd.h>
//子进程返回0,父进程返回子进程的ID,出错返回-1
pid_t fork(void);
进程调用fork,当控制转移到内核中的fork代码后,内核将会:
- 分配新的内存块和内核数据结构给子进程;
- 拷贝父进程部分数据结构内容给子进程;
- 添加子进程到系统进程列表中;
- fork返回,开始调度器调度;
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid;printf("Before: pid is %d\n", getpid());pid = fork();if(pid == -1){perror("fork");exit(-1);}printf("After: pid is %d, fork return %d\n", getpid(), pid);sleep(1);return 0;
}
[wz@192 Desktop]$ ./target
Before: pid is 21739
After: pid is 21739, fork return 21740
After: pid is 21740, fork return 0
- fork前,父进程独立执行;
- fork后,父子进程分流执行;父子谁先执行完全由调度器决定;
写时拷贝
通常父子代码共享,数据也共享(父子在不写入时);当有任意一方写入时,便以写实拷贝的方式各自一份副本,从而保证父子进程的独立性;
二,进程终止
- 代码运行结束,结果正确,退出码为0;
- 代码运行结束,结果不正确,退出码非0;
- 代码异常终止;
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{int i=0;for(i;i<200;i++){printf("%d:%s\n",i,strerror(i));}return 0;
}
[wz@192 Desktop]$ ./target
0:Success
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted system call
5:Input/output error
6:No such device or address
7:Argument list too long
8:Exec format error
9:Bad file descriptor
10:No child processes
11:Resource temporarily unavailable
12:Cannot allocate memory
13:Permission denied
14:Bad address
15:Block device required
16:Device or resource busy
17:File exists
18:Invalid cross-device link
19:No such device
20:Not a directory
21:Is a directory
22:Invalid argument
23:Too many open files in system
24:Too many open files
25:Inappropriate ioctl for device
26:Text file busy
27:File too large
28:No space left on device
29:Illegal seek
30:Read-only file system
31:Too many links
32:Broken pipe
33:Numerical argument out of domain
34:Numerical result out of range
35:Resource deadlock avoided
36:File name too long
37:No locks available
38:Function not implemented
39:Directory not empty
40:Too many levels of symbolic links
41:Unknown error 41
42:No message of desired type
43:Identifier removed
44:Channel number out of range
45:Level 2 not synchronized
46:Level 3 halted
47:Level 3 reset
48:Link number out of range
49:Protocol driver not attached
50:No CSI structure available
51:Level 2 halted
52:Invalid exchange
53:Invalid request descriptor
54:Exchange full
55:No anode
56:Invalid request code
57:Invalid slot
58:Unknown error 58
59:Bad font file format
60:Device not a stream
61:No data available
62:Timer expired
63:Out of streams resources
64:Machine is not on the network
65:Package not installed
66:Object is remote
67:Link has been severed
68:Advertise error
69:Srmount error
70:Communication error on send
71:Protocol error
72:Multihop attempted
73:RFS specific error
74:Bad message
75:Value too large for defined data type
76:Name not unique on network
77:File descriptor in bad state
78:Remote address changed
79:Can not access a needed shared library
80:Accessing a corrupted shared library
81:.lib section in a.out corrupted
82:Attempting to link in too many shared libraries
83:Cannot exec a shared library directly
84:Invalid or incomplete multibyte or wide character
85:Interrupted system call should be restarted
86:Streams pipe error
87:Too many users
88:Socket operation on non-socket
89:Destination address required
90:Message too long
91:Protocol wrong type for socket
92:Protocol not available
93:Protocol not supported
94:Socket type not supported
95:Operation not supported
96:Protocol family not supported
97:Address family not supported by protocol
98:Address already in use
99:Cannot assign requested address
100:Network is down
101:Network is unreachable
102:Network dropped connection on reset
103:Software caused connection abort
104:Connection reset by peer
105:No buffer space available
106:Transport endpoint is already connected
107:Transport endpoint is not connected
108:Cannot send after transport endpoint shutdown
109:Too many references: cannot splice
110:Connection timed out
111:Connection refused
112:Host is down
113:No route to host
114:Operation already in progress
115:Operation now in progress
116:Stale file handle
117:Structure needs cleaning
118:Not a XENIX named type file
119:No XENIX semaphores available
120:Is a named type file
121:Remote I/O error
122:Disk quota exceeded
123:No medium found
124:Wrong medium type
125:Operation canceled
126:Required key not available
127:Key has expired
128:Key has been revoked
129:Key was rejected by service
130:Owner died
131:State not recoverable
132:Operation not possible due to RF-kill
133:Memory page has hardware error
134:Unknown error 134
135:Unknown error 135
136:Unknown error 136
137:Unknown error 137
138:Unknown error 138
进程常见退出方法:
- 正常终止,可通过 echo $? 查看最近一次执行程序退出码;
- main返回,return 0代表进程退出,0退出码表示成功;给系统查看,以确认进程是否正确;非main函数的return不受终止进程,是结束函数;
- exit,任意位置调用此函数,都会直接终止进程;
- _exit,与exit类型,但此函数不会刷新缓冲区等处理工作,直接终止进程;
- 异常退出;
- ctrl + C,信号终止;
退出码可自定义,也可使用系统错误码;
#include <unistd.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
//status 定义了进程终止状态,父进程通过wait来获取该值;
//虽然status为int,但仅低8位可被父进程使用,_exit(-1)执行echo $?结果为255;
#include <stdio.h>
#include <stdlib.h>
int main()
{printf("hello");exit(0); return 0;
}
[wz@192 Desktop]$ ./target
hello[wz@192 Desktop]$
#include <stdio.h>
#include <stdlib.h>
int main()
{printf("hello");_exit(0); return 0;
}
[wz@192 Desktop]$ ./target
[wz@192 Desktop]$
return退出
一种常见的退出进程方法,执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当作exit的参数;
进程终止的核心思想,就是归还资源;
- 释放曾经为管理进程所维护的所有数据结构对象;
- 不是真的把数据结构对象销毁,而是设置为不用状态,保存起来,“数据结构池”;
- 释放程序代码和数据所占的内存空间;
- 不是将代码和数据清空,把内存设置为无效即可;
- 取消曾经该进程的链接关系;
三,进程等待
进程等待的必要性
- 子进程退出,父进程如不管不顾,就可能造成僵死进程,进而造成内存泄露;
- 进程进入僵死状态,将无能为力,即使是kill -9,因为无法杀死一个已经死亡的进程;
- 父进程交派给子进程的任务完成状况需知道,如子进程运行完,其结果对错与否,是否正常退出;
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息;
pid_t wait(int*status)
- 返回值,成功,返回被等待进程pid;失败,返回-1;
- 参数,获取子进程退出状态,不关心可设置为NULL;
#include<sys/types.h>
#include<sys/wait.h>pid_t wait(int*status);
pid_ t waitpid(pid_t pid, int *status, int options)
- 返回值
- 正常返回的时候,waitpid返回收集到的子进程的进程PID;
- 如设置了选项WNOHANG,而调用中waitpid方向没有已退出的子进程可收集,返回0;
- 如调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
- 参数
- pid,-1等待任一个子进程,与wait等效;>0等待其进程ID与pid相等的子进程;
- status
- WIFEXITED(status),若为正常终止子进程进程返回的状态,则为真;
- WEXITSTATUS(status),若WIFEXITED非零,提取子进程退出码;
- options,WNOHANG,若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待;若正常结束,则返回该子进程的ID;
#include<sys/types.h>
#include<sys/wait.h>pid_ t waitpid(pid_t pid, int *status, int options);
- 若子进程已退出,调用wait/waitpid时,wait/waitpid会立即返回,并释放资源,获得子进程退出信息;
- 如在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞;
- 如不存在该子进程,则立即出错返回;
获取子进程status
- wait/waitpid都有一个status参数,此参数为输出型参数,由操作系统填充;
- 如传递NULL,表示不关心子进程的退出状态信息;否则,操作系统会根据该参数,将子进程发退出信息反馈给父进程;
- status不能简单的当作整型看待,可当作位图;