进程的创建和控制

我们已经了解了进程的基本概念,今天我们来看下怎样创建和控制进程吧!

1. 进程的创建

(1)fork()函数

在Linux中,fork 是非常重要的系统函数,它从已经存在的进程中创建一个新的进程。新进程为子进程,原进程为父进程。

函数原型:

返回值:子进程返回0,父进程返回子进程的id ,出错返回-1.

我们先利用fork 函数创建一个进程;

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7         pid_t pid;
  8 
  9         printf("before: pid is %d\n",getpid());
 10 
 11         pid=fork();
 12         if(pid==-1)
 13         {       perror("fork");
 14                 exit(1);
 15         }
 16         printf("after:pid is %d,fork return %d\n" ,getpid(),pid);
 17         sleep(1);
 18         return 0;                                                           
 19 }
 20 

看运行结果:

首先,我们可以看到这里有三行输出,一行before,两行after。before先打印了进程2544的信息,然后after又打印了进程2544的信息,同时也打印了进程2545的信息。这是为什么呢?因为fork之前父进程独立运行,fork之后,父子进程两个执行流分别执行。如下图:

其次,我们可以看到父进程返回的是子进程的id,子进程返回的是0.

fork的常规用法:

(1)一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如:父进程等待客户端请求,生成子进程处理请求。

(2)一个进程要执行不同的程序,例如:子进程从fork返回后,调用exec函数。

fork调用失败的原因

(1)系统中的进程太多。

(2)实际用户的进程数超出了限制。

注意:通常,使用fork之后,操作系统会给子进程分配PCB, 虚拟地址空间,用户级页表。而父进程和子进程的代码共享,数据也是共享的;但是当任意一方开始写入时,便以写时拷贝的方式各自拥有数据。

(2)vfork()函数

功能:创建一个子进程

返回值:父进程返回子进程的id,子进程返回0;出错返回-1;

我们利用vfork函数创建进程:

  5 int glob=100;
  6 int main()
  7 {
  8         pid_t pid;
  9         pid=fork();
 10         if(pid==-1)
 11         {       perror("fork");
 12                 exit(1);
 13         }
 14         if(pid==0)
 15         {
 16             sleep(5);
 17             glob=200;
 18             printf("child glob %d\n",glob);
 19             exit(0);
 20         }
 21         else
 22             printf("parent glob %d\n",glob);
 23 
 24         return 0;
 25 }

运行结果:

我们可以看到,子进程直接改变了父进程的值,这是因为子进程在父进程的虚拟地址空间运行

(3)fork 和 vfork 的区别

1)vfork 用于创建一个子进程,而子进程和父进程共享地址空间。fork的子进程具有独立的虚拟地址空间。

2)vfork 保证子进程先运行,在它调用exec或者(exit)之后父进程才可能被调度执行。fork 的子进程和父进程谁先执行完全由调度器决定。

2. 进程终止

(1)进程退出场景

代码运行完毕,结果正确;

代码运行完毕,结果不正确;

代码异常终止。

(2)进程常见退出方法

1)正常终止:

从main函数返回;调用 exit 函数和 _exit 函数 。

2)异常退出:

ctrl + c,信号终止;

3)return 退出:

return 退出是一种常见的退出进程方法,执行return (n)等于执行exit (n),因为调用main 的运行时函数会将 main 的返回值当作exit 的参数。

(3)exit 函数和 _exit 函数

exit 函数

函数原型:#include <unistd.h>

         void exit( int status);

参数:status 定义了进程的终止状态,父进程通过wait 来获取该值。
_exit 函数

函数原型:#include <unistd.h>

         void _exit (int status);

exit 函数最后也会调用 _exit 函数,但在调用exit 之前,还做了以下工作:

1.执行用户通过atexit 或者on_exit 定义的清理函数;

2.关闭所有打开的流,所有的缓存数据均被写入;

3.调用_exit 函数;

3. 进程等待

(1)为什么要有进程等待呢?

1)在前面讲过,子进程如果退出,父进程不管不顾,子进程就成为僵尸进程,就会造成内存泄漏的问题。

2)而僵尸进程是刀枪不入的,就连kill -9(9号信号)也无能为力,没有办法杀死。

3)父进程派发给子进程的任务是否被完成,父进程需要知道。例如:子进程在运行过程中,结果是对是错,或者是否正常退出。

4)父进程通过进程等待的方式,回收子进程资源,获取子进程的退出信息。

(2)进程等待的方法

wait 方法

函数原型:#include <sys/types.h>

                #include <sys/wait.h>

pid_t wait ( int *status);

参数:输出型参数,获取子进程的退出状态,不关心则可以设置为NULL;

返回值:成功返回被等待的进程pid ,失败返回 -1.

代码实现wait

  1 #include <sys/wait.h>                                                       
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 
  7 int main()
  8 {
  9     pid_t pid;
 10     pid =fork();
 11     if(pid ==-1)
 12     {
 13         perror("fork\n");
 14         exit(1);
 15     }
 16 
 17     if(pid ==0)
 18     {
 19         sleep(20);
 20         exit(10);
 21     }
 22     else{
 23         int st;
       }
 16 
 17     if(pid ==0)
 18     {
 19         sleep(20);
 20         exit(10);
 21     }
 22     else{
 23         int st;
 24         int ret=wait(&st);
 25 
 26         if(ret>0&&(st&0x7F)==0){
 27             printf("child exit code:%d\n",(st>>8)&0xFF);
 28         }                                                                   
 29         else if(ret>0)
 30         {
 31             printf("sig code:%d\n",st&0x7F);
 32         }
 33     }
 34 }
                   
运行结果:

waitpid 方法

函数原型:pid_t waitpid (pid_t pid, int* status,int options);

参数:   pid :

          pid=-1,等待任一个子进程,与wait 等效;

          pid > 0,等待其进程id 与pid 相等的子进程。

        status:

           WIFEXITED(status): 若为正常终止子进程的状态,则为真。(查看进程是否是正常退出的)

           WEXITSTATUS(status ):若WIFEXITED非0,提取子进程退出码。(查看进程退出码 )
       options:

           WNOHANG: 若pid 指定的子进程没有结束,则wait_pid函数返回0,不予以等待。若正常结束,返回该子进程的id。

waitpid代码实现进程阻塞等待方式

 
  1 #include <stdio.h>                                                          
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/types.h>
  5 
  6 int main()
  7 {
  8     pid_t pid=fork();
  9     if(pid<0)
 10     {
 11         perror("fork");
 12         return 1;
 13     }
 14     else if(pid==0){
 15         printf("child is run,pid is :%d\n",getpid());
 16         exit(257);}
 17     else{
 18         int status=0;
 19         pid_t ret =waitpid(-1,&status,0);
 20         printf("this is test for wait\n");
 21         if(WIFEXITED(status)&& ret==pid){
 22             printf("wait child 5s success,child return code is:%d\n",WEXITST    ATUS(status));
 23           }
 24         else
 25         {  
 26             printf("wait child failed,return\n");
 27             return 1;
 28         }
 29     }
 30     return 0;
 31 }          

运行结果:

4. 进程程序替换

(1) 替换函数

有六种以exec开头的替换函数,统称为exec函数:

#include <unistd.h>

int execl (const char* path,const char* arg, ...);   // l(list) 表示参数采用列表;

int execlp( const char* path,const char *arg, ...);  //p (path) 有 p 自动搜索环境变量PATH;

int execle( const char* path, const char *arg, ... ,char *const envp[ ] );  //e(env) 表示自己维护环境变量;

int execv (  const char* path , char *const argv[ ] );//v( vector ),参数用数组;
int execvp( const char* file , char *const argv[ ] );
int execve (  const char* path , char *const argv[ ] , char *const envp[ ] ); 

注:这些函数如果调用成功,则加载新的程序从启动代码开始执行,不再返回。

      如果调用出错,则返回 -1;

      exec 函数只有出错返回值没有成功返回值。

(2)exec 调用举例

     int main()
  4 {
  5     char* const argv[]={"ps","-ef",NULL};
  6     char* const envp[]={"PATH=/bin:/usr/bin","TERM=console",NULL};
  7 
  8     execl("/bin/ps","ps","-ef",NULL);
  9 
 10     execlp("ps","ps","-ef",NULL);
 11 
 12     execle("ps","ps","-ef",NULL,envp);
 13 
 14     execv("/bin/ps",argv);
 15 
 16     execvp("ps",argv);
 17 
 18     execve("/bin/ps",argv,envp);
 19 
 20     exit(0);
 21 }              

 

 

 

 

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值