• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Linux启动新进程的三种方法

    程序中,我们有时需要启动一个新的进程,来完成其他的工作。

    下面介绍了三种实现方法,以及这三种方法之间的区别。

    1.system函数-调用shell进程,开启新进程

    system函数,是通过启动shell进程,然后执行shell命令进程。

    原型:

    int system(const char *string);

    string:shell命令字符串

    返回值:成功返回命令退出码,无法启动shell,返回127错误码,其他错误,返回-1。

    代码示例如下:

    process_system.c

    #includestdlib.h>                               
    #includestdio.h>
    int main()
    {
        printf("Running ps with system\n");
        int code = system("ps au");//新进程结束后,system函数才返回
        //int code = system("ps au");//system函数立即返回
        printf("%d\n",code);
        printf("ps Done\n");
        exit(0);
    }

    输出结果:

    system函数,在启动新进程时,必须先启动shell进程,因此使用system函数的效率不高。

    2.exec系列函数-替换进程映像

    exec系列函数调用时,启动新进程,替换掉当前进程。即程序不会再返回到原进程,

    除非exec调用失败。

    exec启动的新进程继承了原进程的许多特性,如在原进程中打开的文件描述符在新进程中仍保持打开。

    需要注意的是,在原进程中打开的文件流在新进程中将关闭。原因在于,我们在前面讲过进程间通信的方式,进程之间需要管道才能通信。

    原型:

    int execl(const char *path,const char *arg0,...,(char*)0);
    int execlp(const char *file,const char *arg0,...,(char*)0);
    int execle(const char *path,const char *arg0,...,(char*)0,char *const envp[]);
    int execv(cosnt char *path,char *const argv[]);
    int execvp(cosnt char *file,char *const argv[]);
    int execve(cosnt char *path,char *const argv[],char *const envp[]);

    path/file:进程命令路径/进程命令名

    argc:命令参数列表

    envp:新进程的环境变量

    代码示例如下:

    process_exec.c

    #includestdio.h>
    int main()
    {
      printf("Running ps with execlp\n");
      execlp("ps","ps","au",(char*)0);
      printf("ps done");
      exit(0);
    }
    
    

    输出结果:

    可以看出,调用execlp函数后,原进程被新进程替换,原进程中printf("ps done");没有被执行到。

    3.fork函数-复制进程映像

    1)fork函数的使用

    fork和exec的替换不同,调用fork函数,可复制一个和父进程一模一样的子进程。

    执行的代码也完全相同,但子进程有自己的数据空间,环境和文件描述符。

    原型:

    pid_t fork();

    父进程执行时,返回子进程的PID

    子进程执行时,返回0

    代码示例如下:

    process_fork.c

    #includestdio.h>
    #includesys/types.h>
    int main()
    {
      pid_t pid = fork();
      switch(pid)
      {
        case -1:
          perror("fork failed");
          exit(1);
          break;
        case 0:
          printf("\n");
          execlp("ps","ps","au",0);
          break;
        default:
          printf("parent,ps done\n");
          break;
      }
      exit(0);
    }
    
    

    输出结果:

    调用fork函数后,新建了一个子进程,拷贝父进程的代码,数据等到子进程的内存空间。父进程和子进程执行互不影响。使用fork函数的返回值,来区分执行的是父进程,还是子进程。

    2)僵尸进程

    子进程退出后,内核会将子进程置为僵尸状态。此时,子进程只保留了最小的一些内核数据结构,如退出码,以便父进程查询子进程的退出状态。这时,子进程就是一个僵尸进程。

    在父进程中调用wait或waitpid函数,查询子进程的退出状态,可以避免僵尸进程。

    原型:

    pid_t wait(int *stat_loc);
    pid_t waitpid(pid_t pid,int *stat_loc,int options);

    stat_loc:若不是空指针,则子进程的状态码会被写入该指针指向的位置。

    pid:等待的子进程的进程号pid

    options:标记阻塞或非阻塞模式

    返回值:成功返回子进程的pid,若子进程没有结束或意外终止,返回0

    wait:阻塞模式(使用了信号量),父进程调用wait时,会暂停执行,等待子进程的结束。

    wait调用返回后,子进程会彻底销毁。

    waitpid:与wait不同的是,

    a.可以表示四种不同的子进程类型

         pid==-1 等待任何一个子进程,此时waitpid的作用与wait相同

      pid >0 等待进程ID与pid值相同的子进程

      pid==0 等待与调用者进程组ID相同的任意子进程

      pid-1 等待进程组ID与pid绝对值相等的任意子进程

    b.当options的值为WNOHANG时,为非阻塞模式,即waitpid会立即返回

    此时,可以循环查询子进程的状态,若子进程未结束,waitpid返回,做其他工作。

    这样提高了程序的效率。

    wait函数使用示例如下:

    process_fork3.c

    #includewait.h>
    #includestdio.h>
    #includesys/types.h>
    int main()
    {
      pid_t pid = fork();
      int stat = 0;
      switch(pid)
      {
        case -1:
          perror("fork failed");
          exit(1);
          break;
        case 0:
          printf("\n");
          exit(0);
          break;
        default:
          pid = wait(stat);
          printf("Child has finished:PID=%d\n",pid);
          printf("parent,ps done\n");
          break;
      }
      exit(0);
    }
    
    

    输出结果:

    waitpid函数使用示例如下:

    process_fork2.c

    #includewait.h>
    #includestdio.h>
    #includesys/types.h>
    int main()
    {
      pid_t pid = fork();
      int stat = 0;
      switch(pid)
      {
        case -1:
          perror("fork failed");
          exit(1);
          break;
        case 0:
          printf("\n");
          execlp("ps","ps","au",0);
          break;
        default:
          do
          {
            pid = waitpid(pid,stat,WNOHANG);
            if(pid==0)
            {
              printf("parent do something else.\n");
              sleep(1);
            }
          }while(pid==0);
          printf("Child has finished:PID=%d\n",pid);
          printf("parent,ps done\n");
          break;
      }
      exit(0);
    }
    
    

    输出结果:

    4.启动新进程三种方法的比较

    1)system函数最简单,启动shell进程,并在shell进程中执行新的进程。

    效率不高,system函数必须等待子进程返回才能接着执行。

    2)exec系列函数用新进程替换掉原进程,但不会返回到原进程,除非调用失败。

    该函数继承了许多原进程的特性,效率也较高。

    3)fork函数,复制一个子进程,和父进程一模一样,但是拥有自己的内存空间。父子进程执行互不影响。需要注意僵尸子进程的问题。

    以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

    您可能感兴趣的文章:
    • 解决Linux下php-fpm进程过多导致内存耗尽问题
    • linux下如何创建守护进程的步骤
    • 详解Linux如何查看当前占用CPU或内存最多的几个进程
    • Linux查找占用的端口,并杀死进程的方法
    • Linux启动新进程的几种方法及比较
    • linux下的C\C++多进程多线程编程实例详解
    • Linux创建进程达到65535的方法
    上一篇:Linux启动新进程的几种方法及比较
    下一篇:远程SSH连接服务与基本排错经验总结
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Linux启动新进程的三种方法 Linux,启动,新进程,新,进程,