【Linux】进程创建

1.进程创建

  1. 分配新的内存块和内核数据结构给子进程
  2. 将父进程部分的数据结构拷贝至子进程
  3. 添加子进程到系统进程列表中
  4. fork返回,开始调度器调度

创建子进程除了fork还有vfork:

  1. vfork 用于创建一个子进程,而子进程和父进行共享地址空间,fork的子进程有独立的地址空间
  2. vfork保证子进程先运行,在它调用exec或exit(return不行)之后父进程才可能被调度运行。vfork也有两个返回值
注意:在任何一个系统实现的vfork都有问题,所有不要用vfork,就算是fork实现了写实拷贝,也没有vfork高效

2.进程终止

进程提出场景:

  1. 代码运行完毕,结果正确
  2. 代码运行完毕,结果不正确
  3. 代码没跑完,异常终止(while(1)永远跑不完,只能ctrl +异常终止,absort,kill pid)
进程常见退出方法:

正常终止:(可以通过echo  $?查看进程退出码,只保存离它最近的退出码

  1. 从main返回
  2. 调用exit
  3. _exit(系统调用,强制退出)

return只有在main函数中才会退出进程,参数表示退出码,而exit()在任何时候使用都会退出进程,参数表示退出码,退出码表示进程退出信息,除了exit()可以退出进程,_exit()也可以,但_exit()是强制退出,而exit()退出时还会做些收尾工作,像刷新缓冲区等


异常退出:

  1. ctrl +c,信号终止
  2. absort
  3. kill pi

3.进程等待(子进程必须被等待)

进程等待的重要性

  1. 子进程退出,父进程不管不顾,就可能造成僵尸进程,进而造成内存泄漏
  2.  我们要知道父进程派给子进程的任务完成情况,如:子进程运行完成,结果是对还是不对,或者是否正常退出等
  3. 父进程通过进程等待的方式回收子进程资源,获取子进程退出信息
等待方法:
(1)pid_t wait(int *status)      //  阻塞,直到有一个子进程死亡,回收返回

注:wait(NULL)可以回收僵尸进程,但是只能回收一个

需要了解的宏:

  • WEXITSTATUS(status):得到子进程的退出码
  • WIFEXITED(status):如果正常退出,返回真    两个经常搭配使用,先判断后使用
  • WIFSIGNALED(status):如果是信号令其死亡,返回真
  • WIERMSIG(status):获得杀死进程的的信号

(2)pid_t  wait(pid_t pid , int *status  , int options);//第一个参数为要等待的子进程pid;如果是-1,表示等待任意子进程,第三个参数默认为0;waitpid()也可以回收僵尸进程

返回值:当正常返回的时候waitpid返回收集到的子进程的pd,如果被设置为WNOHANG,返回0,出错返回-1

参数pid:


等待情况:

  • 如果子进程已经退出,调用wait/waitpid,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
  • 如果子进程不存在,则立即出错返回
4.进程替换
想想在一个shell终端,我们敲下ls命令后,ls命令是怎样被执行的呢,很容易想到,ls的代码开始肯定在磁盘上,那么它是如何及加载到内存然后被执行的呢,这里就用到了进程替换
如果shell终端直接将ls的代码替换它自己,那么ls执行失败,它自己也会崩掉,所以它一定是创建了一个子进程,自己就指向原代码,让ls的代码将子进程的代码替换,子进程执行ls的代码

注:进程替换并没有创建新进程,所以pid不变
// 用file指定的程序替换当前进程
int execvp(const char *file,  // 可执行程序的名字
		char *const argv[]);  // main函数的命令行参数
成功,没有返回值,失败,返回-1

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 *filename, char *const argv[],
                  char *const envp[]);

p : PATH
v : vector
l : list
e : environment




execvp第一个参数为替换文件,第二个参数为main函数的命令行参数,第一个是替换程序的可执行名,必须以NULL结尾

小案例

(1)mysystem


这里就是用fork创建子进程,子进程用execvp进程替换,父进程用waitpid阻塞等待子进程

(2)myshell


猜你喜欢

转载自blog.csdn.net/lw__sunshine/article/details/81059972
今日推荐