《Linux》进程和信号
文章目录
一、什么是进程
- UNIX标准把进程定义为:“一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。”
- 正在运行的程序或进程由程序代码、数据、变量(占用着系统内存)、打开的文件(文件描述符)和环境构成。
二、进程的结构
- 进程标识符PID(2-32768)数字1一般为特殊进程init保留的,init进程负责管理其他进程。
- 程序代码(被保存在一个磁盘文件,以只读方式加载到内存中,可以被多个进程安全地共享。
- 共享库函数
- 栈空间(用于保留函数中的局部变量和控制函数的调用与返回。)
- 环境空间(包含专门为这个进程建立的环境变量)
- 程序计数器(用来记录进程执行到的位置,即在执行线程中的位置)
2.1、进程表
2.2、查看进程
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:43 ? 00:00:05 /sbin/init splash
root 2 0 0 08:43 ? 00:00:00 [kthreadd]
root 3 2 0 08:43 ? 00:00:00 [rcu_gp]
root 4 2 0 08:43 ? 00:00:00 [rcu_par_gp]
root 6 2 0 08:43 ? 00:00:00 [kworker/0:0H-kb]
root 7 2 0 08:43 ? 00:01:06 [kworker/0:1-eve]
root 9 2 0 08:43 ? 00:00:00 [mm_percpu_wq]
root 10 2 0 08:43 ? 00:00:01 [ksoftirqd/0]
root 11 2 0 08:43 ? 00:00:03 [rcu_sched]
root 12 2 0 08:43 ? 00:00:01 [migration/0]
root 13 2 0 08:43 ? 00:00:00 [idle_inject/0]
^C
2.3、系统进程
ps ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:05 /sbin/init splash
2 ? S 0:00 [kthreadd]
3 ? I< 0:00 [rcu_gp]
4 ? I< 0:00 [rcu_par_gp]
6 ? I< 0:00 [kworker/0:0H-kb]
7 ? I 1:06 [kworker/0:1-eve]
9 ? I< 0:00 [mm_percpu_wq]
10 ? S 0:01 [ksoftirqd/0]
11 ? I 0:03 [rcu_sched]
12 ? S 0:01 [migration/0]
13 ? S 0:00 [idle_inject/0]
14 ? S 0:00 [cpuhp/0]
15 ? S 0:00 [kdevtmpfs]
16 ? I< 0:00 [netns]
17 ? S 0:00 [rcu_tasks_kthr
^C
- init进程
2.4、进程调度
三、启动新进程
int system(const char *string); //<stdlib.h>
作用:运行以字符串string参数的形式传递给它的命令。和在shell中运行 sh -c string 一样。
如果无法启动shell来运行这个命令,system返回错误代码127;
如果其他错误,返回-1.否则,将返回该命令的退出码。
3.1、替换进程映像(exec系列函数)
char **environ;
int execl(const char *path, const char *arg0, ..., (char *)0);
int execlp(const char *file, const char *arg0, ..., (char *)0);
int execle(const char *path, const char *arg0, ..., (char *)0, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
//<unistd.h>
以字母p结尾函数通过搜索PATH环境变量来查找新程序的可执行路径。
如果可执行文件不在PATH定义路径中,则需要把包括目录在内的使用绝对路径的文件名作为参数传递给函数
全局变量environ可用来把一个值传递到新的程序环境。
execle和execve可以通过参数envp传递字符串数组作为新程序环境变量。
- 示例:
#include<unistd.h>
char *const ps_argv[]={"ps", "ax", 0};
char *const ps_envp[]={"PATH=/bin:/usr/bin", "TERM=console", 0};
execl("/bin/ps", "ps", "ax", 0);//包括目录在内的绝对路径的文件名
execlp("ps", "ps", "ax", 0);//在系统路径下查找,给出ps命令名称即可
execle("/bin/ps", "ps", "ax", 0, ps_envp);
execv("/bin/ps", ps_argv);
execvp("ps", ps_argv);
execve("/bin/ps", ps_argv, ps_envp);
- 新进程的PID、PPID和nice值与原先完全一样
- 一般情况下,exec函数是不会返回,除非发生了错误。
- 出现错误时,exec函数返回-1,并会设置错误变量errno
- 由exec启动的新进程继承了原进程的许多特性
- 在原进程中已打开文件描述符在新进程中仍将保持打开
- 任何在原进程中已打开的目录流都将在新进程中被关闭
3.2、复制进程映像
pid_t fork(void); //<sys/types.h> <unistd.h>
在父进程的fork调用返回是新的子进程的PID。新进程和原进程一样,继续执行
子进程中的fork调用返回是0
如果fork失败,它将返回-1;
失败通常是因为父进程所拥有子进程数目超过了规定的限制(CHILD_MAX),errno被设为EAGAIN
如果是因为进程表中没有足够的空间用于创建新的表单或内存不足,errno被设为ENOMEN
- 示例:
- 运行结果:
3.3、等待一个进程
等待1 (父进程等待子进程结束)
pid_t wait(int *stat_loc); //<sys/types.h> <sys/wait.h>
- wait将暂停父进程直到它的子进程结束为止
- 返回子进程的PID,它通常是已结束的子进程的PID
- 状态信息允许父进程了解子进程的退出状态,及子进程的main函数返回值或子进程中的exit函数的退出码。
- 如果stat_loc不是空指针,状态信息将被别入它指向的位置。
- 示例:
等待2 (等待某个特定的进程的结束)
pid_t waitpid(pid_t pid, int *stat_loc, int options);
// <sys/types.h> <sys/wait.h>
- pid参数指定需要等待的子进程的PID。如果它的值是-1,waitpid将返回任一子进程的信息
- 如果stat_loc不是空指针,waitpid将把状态信息写到它指向的位置。
- option参数可用来改变waitpid的行为,可以是下面0个或多个的按位或:
WNOHANG 如果子进程没有结束或意外中止,则返回0,程序继续,否则返回结束进程的pid。
WUNTRACED 如果一个子进程中止,则返回。
WCONTINUED 如果一个中止的子进程恢复,则返回。
3.4、僵尸进程–zombie–defunct
- 定义:子进程先于父进程结束并成为僵尸进程,等待父进程结束。
- 如果此时父进程异常终止,子进程将自动将PID为1的进程(init)作为自己的父进程。
- 僵尸进程将一直保留在进程表中直到被init进程发现并释放。