目录
之前说了什么是进程,今天我们来讲讲怎么创建进程,我们可以通过系统调用来创建函数。
pid_t fork(); 该函数可以创建一个子进程 如果创建成功就对子进程返回0 对父进程返回子进程的pid
如果创建失败,就给父进程返回 -1
那么为什么要创建一个子进程呢?
1.父进程希望复制自己,使父子进程执行不同的代码。
2.父子进程分别执行不同的程序
fork失败的情况
1.进程过多
2.实际用户的进程数超过限制
进程退出的场景都有哪些呢?
1.程序运行成功,结果对
2.程序运行成果,结果不对
3.程序异常终止
程序退出不管成功与否都会有一个退出码,我们可以通过退出码判断程序出错的原因。大家再写c程序的时候是不是都很纳闷,为什么要 return 0;呢?我return别的不可以吗?通过上面的讲述我们知道,每个进程退出都会有他的退出码,这个退出码可以标识进程执行情况,在Linux下 我们可以echo $?(正常执行)查询最近进程退出码。
那么这些退出码都有什么含义呢?系统中其实有这些对应的信息(strerror()),我们也可以自己设置。
除了通过return 返回外,还可以通过exit(),_exit()函数返回,return 0 本质也是调用了exit()函数,将return的值作为exit()的参数。
上次讲过一个僵尸进程,就是子进程结束了但是父进程还在执行,一直不回收子进程的资源,这样就会造成子进程僵尸,进而造成内存泄漏,即使使用kill信号也杀不它 因为他已经死亡。父进程派给子进程的任务完成的怎么样呢?就需要父进程去等待子进程的推出结果。今天介绍两个函数 pid_t wait(int* status) pid_t waitpid(pid_t id, int*status, int options )
pid_t wait(int* status): 等待随机一个子进程 通过status返回子进程的退出信息,返回值返回子进程的pid 属于阻塞式的等待,就是说不等到子进程退出就不会执行该行下面的代码了。
那么status真的就是进程的退出码了吗?答案是错的,status包含了很多退出信息,今天说两个我知道的。status是32位的,其中次低8位保存的是退出码,低7位是进程读到的信号。第8位是core dump标志
pid_t waitpid(pid_t id, int*status, int options ): id 是要等待子进程的pid 如果传入-1则表示随即等待一个子进程,status和上述一样,options是等待模式 有 0 和WNHANG(宏 定义1) 0 表示阻塞式等待,WNHANG表示非阻塞式等待,就是说可以边等待子进程返回 边执行自己的程序(运用循环)。返回值 成功等到返回子进程pid 没有等到返回0 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在。
如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。 如果不存在该子进程,则立即出错返回。
所谓进程替换,就是父子进程要执行不同的程序了,父进程调用fork()创建子进程,操作系统通过函数接口(exec系列函数)将磁盘上的可执行程序加载到物理内存上去,再通过页表映射到虚拟内存上去,cpu就可以执行这个程序,exec成功调用会把从调用位置包括自己向下所有代码和数据都进行替换如果失败就会返回-1 成功是不会返回的,因为原来的exec已经被替换掉了所以返回也没什么用
#include <unistd.h>`
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[]);
...(可变参数列表)可以传入多个不定个数的参数 path是可执行程序所在路径 arg表示命令行参数。最后要以NULL结尾。
#include<stdio.h>
#include<unistd.h>
int main()
{
execl("/usr/bin/ls","ls","-a","-l",NULL);
return 0;
}
这样就通过execl执行了ls
我们也可以用execv来执行其中的argv[]存的是 命令行参数最后一个位置是NULL
#include<stdio.h>
#include<unistd.h>
int main()
{
char* argv[32] = {
"ls",
”-a",
“-l",
NULL
};
execv("/usr/bin/ls",argv);
return 0;
}
#include<stdio.h>
#include<unistd.h>
int main()
{
char* argv[32] = {
"ls",
"-a",
"-l",
NULL
};
execvp(argv[0],argv);
return 0;
}