进程
- 一个终端等于一个进程
- 一个程序经常同时启动多个进程以并行多个任务。这就引入进程间通讯的概念
- 只要系统内存足够,理论上可用运行无数个进程
查看进程¶
- PID:ProcessID,16 位正整数,默认 2~32768
- 1 为特殊进程 init,负责管理其他进程
- PID 自动按顺序分配
父进程¶
- 父进程的进程号(PID)即为子进程的父进程号(PPID)
- 用户可以通过调用 getppid() 函数来获得当前进程的父进程号
进程与程序¶
- 程序是静态文件,或称可执行文件
- 进程是动态实体,是程序执行的具体实例。它包括了运行环境、CPU、外设等
- 一个程序可用实例化很多个进程
- 每个进程都有单独的地址空间
进程状态¶

进程创建¶
- system()
- 模拟调用 shell 终端运行一个程序
- 阻塞的,需要立刻返回在指令后面加 & 运行,
ls & - 返回结果不可预料
- fork()

exec 族函数¶
如果父子进程都一样的话,子进程能干的父进程也能干。为了让子进程做点不一样的事,exec 系列函数就诞生了。
执行完后,原进程除了进程号外,其他内容(内存空间、数据段、代码段、环境变量等)都被替换掉
脱胎换骨、覆盖的意思
int main(void)
{
int err;
printf("this is a execl function test demo!\n\n");
// 必须以 NULL 结尾,效果等同于 ls -la
err = execl("/bin/ls", "ls", "-la", NULL);
// 因为替换了,所以一般不会返回,除非发生错误
if (err < 0) {
printf("execl fail!\n\n");
}
// 由于 exec 是替换,因此 Done 不会被执行
printf("Done!\n\n");
return 0;
}
exec 其他函数原型
int execl(const char *path, const char *arg, ...)
int execlp(const char *file, const char *arg, ...)
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[])
int execve(const char *path, char *const argv[], char *const envp[])
进程终止¶
正常终止: 1. 从 main 返回 2. 调用 exit() 终止 3. 调用 _exit() 终止

异常终止: 1. 调用 abort() 终止 2. 系统信号终止
进程等待¶
当调用 exit() 后,进程变成了僵尸进程(无内存空间、没有可执行代码、不能被调度)。 无论如何,父进程都要回收这个僵尸进程。 调用 wait() 或者 waitpid() 函数其实就是将这些僵尸进程回收, 释放僵尸进程占有的内存空间,并且了解一下进程终止的状态信息。
fork & wait 需要成对出现
函数原型:
代码示例:
int main(void)
{
pid_t pid, child_pid;
int status;
pid = fork(); //(1)
if (pid < 0)
{
printf("Error fork\n");
}
/*子进程*/
else if (pid == 0)
{ //(2)
printf("I am a child process!, my pid is %d!\n\n", getpid());
/*子进程暂停 3s*/
sleep(3);
printf("I am about to quit the process!\n\n");
/*子进程正常退出*/
exit(0); //(3)
}
/*父进程*/
else
{ //(4)
/*调用 wait,父进程阻塞*/
child_pid = wait(&status); //(5)
/*若发现子进程退出,打印出相应情况*/
if (child_pid == pid)
{
printf("Get exit child process id: %d\n", child_pid);
printf("Get child exit status: %d\n\n", status);
}
else
{
printf("Some error occured.\n\n");
}
exit(0);
}
return 0;
}