Linux
环境下,查看筛选进程的shell
命令ps -ef
:查看系统的全部进程ps aux
:查看系统的全部进程ps -ef | grep demo
:从全部进程中,筛选出和 demo
相关的进程kill -9 pid_t
fork()
#include <sys/types.h>
#include <unistd.h>
pid_t
是一个整数,在父进程中,返回值是子进程编号;在子进程中,返回值是0。如果创建失败,则返回 -1。pid_t fork(void);
fork()
函数所创建的子进程是父进程的完整副本,复制了父进程的资源fork()函数后的代码
)#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
pid_t res;
res = fork();
if (res > 0) {
printf("This is parent, pid = %d\n", getpid());
} else if (res == 0) {
printf("This is child, pid = %d\n", getpid());
} else {
perror("fork");
}
return 0;
}
This is parent, pid = 3543
This is child, pid = 3544
vfork()
必备头文件
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
特点:
1、返回值和fork()
函数相同。
2、vfork()
不创建子进程的虚拟地址,直接共享父进程的,从而物理地址也被共享了
3、子进程先运行,在子进程调用 exec(进程替换)
或者exit
之后,父进程被调度执行
举例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int num = 10;
pid_t res;
res = vfork();
if (res > 0) {
printf("This is parent, pid = %d\n", getpid());
num += 10;
printf("num = %d\n", num);
} else if (res == 0) {
printf("This is child, pid = %d\n", getpid());
num += 10;
printf("num = %d\n", num);
exit(0);
} else {
perror("vfork");
}
return 0;
}
打印输出
This is child, pid = 4495
num = 20
This is parent, pid = 4494
num = 30
从输出结果可以看出,子进程先执行,在子进程调用 exit(0)
退出之后,父进程再执行。
并且,父子进程共享 num
变量。
fork()
和vfork()
的不同之处:fork()
复制父进程的页表项,当进行写操作时,内核给子进程分配一个新的内存页面vfork()
与父进程共享页表项,当写操作时,直接写在父进程的内存页面fork()
创建的子进程与父进程之间的执行次序不确定vfork()
是子进程先运行,在子进程调用 exec(进程替换)
或者exit
之后,父进程被调度执行vfork()
保证子进程先运行,在子进程调用exec
或exit
之后父进程才可能被调度运行。如果在exec
函数族有时候,我们需要在子进程中执行其它程序,即替换当前进程映像,这时候会使用exec
函数族中的一些函数。
**作用:**根据指定的文件名找到可执行文件,并用它来取代调用进程的内容(在调用进程内部执行一个可执行文件)
返回值: exec
函数族的函数执行成功后不会返回,只有调用失败了,才会返回-1,回到源程序的调用点接着往下执行。
常用函数:
1、
int execl(const char *pathname, const char *arg, ...);
- pathname: 要执行的可执行文件的路径
- arg: 执行可执行文件所需要的参数列表
arg一般填写当前执行程序的名字,后面依次是可执行程序所需要的参数列表,参数最后要以 NULL 结束。
- 返回值:
当调用失败时,才有返回值,返回-1。
2、
int execlp(const char *file, const char *args, ...);
- 和 execl 基本一致,不过对于file会从环境变量中寻找。
定义: 父进程结束运行,但是子进程还在运行,这样的子进程为孤儿进程(父死子在)。
注意: 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init
,而 init
进程会循环地 wait()
它的已经退出的子进程。这样当一个孤儿进程结束生命周期的时候,init()
进程就会处理它的一切善后工作。
因此,孤儿进程并不会有什么危害。
当子进程结束运行时,内核不会立即释放该进程的进程表表项,以满足父进程后续对该子进程退出信息的查询(如果父进程还在运行)。
在子进程结束运行后,父进程回收子进程状态前,该子进程为僵尸进程。内核资源有限,不允许产生大量的僵尸进程。
僵尸进程不能被 kill -9
杀死。
可以在父进程中使用 wait()
或者 waitpid()
函数,以等待子进程的结束,并获取子进程的返回信息,从而避免了僵尸进程的产生,或者使子进程的僵尸态立即结束。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
- 功能:等待任意一个子进程结束,并回收子进程。
- 参数:wstatus, 进程退出时的状态信息,传入的是一个int类型的指针(传出参数)
- 返回值:
成功:返回被回收的子进程的id
失败:-1(所有子进程都结束,调用函数失败)
注意: 调用 wait()
函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时才被唤醒。
如果没有子进程了,函数立刻返回-1;
如果子进程都已经结束了,也会立即返回,返回 -1。