全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Linux启动新进程的几种方法及比较

有时候,我们需要在自己的程序(进程)中启动另一个程序(进程)来帮助我们完成一些工作,那么我们需要怎么才能在自己的进程中启动其他的进程呢?在Linux中提供了不少的方法来实现这一点,下面就来介绍一个这些方法及它们之间的区别。

一、system函数调用

system函数的原型为:

#include <stdlib.h> 
int system (const char *string); 

它的作用是,运行以字符串参数的形式传递给它的命令并等待该命令的完成。命令的执行情况就如同在shell中执行命令:sh -c string。如果无法启动shell来运行这个命令,system函数返回错误代码127;如果是其他错误,则返回-1。否则,system函数将返回该命令的退出码。

注意:system函数调用用一个shell来启动想要执行的程序,所以可以把这个程序放到后台中执行,这里system函数调用会立即返回。

可以先先下面的例子,源文件为new_ps_system.c,代码如下:

#include <stdlib.h> 
#include <stdio.h> 
int main() 
{ 
  printf("Running ps with system\n"); 
  //ps进程结束后才返回,才能继续执行下面的代码 
  system("ps au");// 1 
  printf("ps Done\n"); 
  exit(0); 
} 

该程序调用ps程序打印所有与本用户有关的进程,最后才打印ps Done。运行结果如下:

如果把注释1的语句改为:system("ps au &");则system函数立即返回,不用等待ps进程结束即可执行下面的代码。所以你看到的输出,ps Done可能并不是出现在最后一行,而是在中间。

一般来说,使用system函数不是启动其他进程的理想手段,因为它必须用一个shell来启动需要的程序,即在启动程序之前需要先启动一个shell,而且对shell的环境的依赖也很大,因此使用system函数的效率不高。

二、替换进程映像——使用exec系列函数

exec系列函数由一组相关的函数组成,它们在进程的启动方式和程序参数的表达方式上各有不同。但是exec系列函数都有一个共同的工作方式,就是把当前进程替换为一个新进程,也就是说你可以使用exec函数将程序的执行从一个程序切换到另一个程序,在新的程序启动后,原来的程序就不再执行了,新进程由path或file参数指定。exec函数比system函数更有效。

exec系列函数的类型为:

#include <unistd.h> 

char **environ; 

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 (const char *path, char *const argv[]); 
int execvp(cosnt char *file, char *const argv[]); 
int execve(const char *path, char *const argv[], char *const envp[]); 

这类函数可以分为两大类,execl、execlp和execle的参数是可变的,以一个空指针结束,而execv、execvp和execve的第二个参数是一个字符串数组,在调用新进程时,argv作为新进程的main函数的参数。而envp可作为新进程的环境变量,传递给新的进程,从而变量它可用的环境变量。

承接上一个例子,如果想用exec系统函数来启动ps进程,则这6个不同的函数的调用语句为:

注:arg0为程序的名字,所以在这个例子中全为ps。

char *const ps_envp[] = {"PATH=/bin:usr/bin", "TERM=console", 0}; 
char *const ps_argv[] = {"ps", "au", 0}; 
 
execl("/bin/ps", "ps", "au", 0); 
execlp("ps", "ps", "au", 0); 
execle("/bin/ps", "ps", "au", 0, ps_envp); 
 
execv("/bin/ps", ps_argv); 
execvp("ps", ps_argv); 
execve("/bin/ps", ps_argv, ps_envp); 

下面我给出一个完整的例子,源文件名为new_ps_exec.c,代码如下:

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
  printf("Running ps with execlp\n"); 
  execlp("ps", "ps", "au", (char*)0); 
  printf("ps Done"); 
  exit(0); 
} 

运行结果如下:

细心的话,可以发现,最后的ps Done并没有输出,这是偶然吗?并不是,因为我们并没有再一次返回到程序new_ps_exec.exe上,因为调用execlp函数时,new_ps_exec.exe进程被替换为ps进程,当ps进程结束后,整个程序就结束了,并没有回到原来的new_ps_exec.exe进程上,原本的进程new_ps_exec.exe不会再执行,所以语句printf("ps Done");根本没有机会执行。

注意,一般情况下,exec函数是不会返回的,除非发生错误返回-1,由exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,但任何在原进程中已打开的目录流都将在新进程中被关闭。

三、复制进程映像——fork函数

1、fork函数的应用

exec调用用新的进程替换当前执行的进程,而我们也可以用fork来复制一个新的进程,新的进程几乎与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境和文件描述符。

fork函数的原型为:

#include <sys/type.h> 
#include <unistd.h> 
 
pid_t fork(); 

注:在父进程中,fork返回的是新的子进程的PID,子进程中的fork返回的是0,我们可以通过这一点来判断父进程和子进程,如果fork调用失败,它返回-1.

继承上面的例子,下面我给出一个调用ps的例子,源文件名为new_ps_fork.c,代码如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
  pid_t pid = fork(); 
  switch(pid) 
  { 
  case -1: 
    perror("fork failed"); 
    exit(1); 
    break; 
  case 0: 
    //这是在子进程中,调用execlp切换为ps进程 
    printf("\n"); 
    execlp("ps", "ps", "au", 0); 
    break; 
  default: 
    //这是在父进程中,输出相关提示信息 
    printf("Parent, ps Done\n"); 
    break; 
  } 
  exit(0); 
} 

输出结果为:

我们可以看到,之前在第二点中没有出现的ps Done是打印出来了,但是顺序却有点不对,这是因为,父进程先于子程序执行,所以先输出了Parent, ps Done,那有没有办法让它在子进程输出完之后再输出,当然有,就是用wait和waitpid函数。注意,一般情况下,父进程与子进程的生命周期是没有关系的,即便父进程退出了,子进程仍然可以正常运行。

2、等待一个进程

wait函数和waitpid函数的原型为:

#include <sys/types.h> 
#include <sys/wait.h> 
 
pid_t wait(int *stat_loc); 
pid_t waitpid(pid_t pid, int *stat_loc, int options); 

wait用于在父进程中调用,让父进程暂停执行等待子进程的结束,返回子进程的PID,如果stat_loc不是空指针,状态信息将被写入stat_loc指向的位置。

waitpid等待进程id为pid的子进程的结束(pid为-1,将返回任一子进程的信息),stat_loc参数的作用与wait函数相同,options用于改变waitpid的行为,其中有一个很重要的选项WNOHANG,它的作用是防止waippid调用者的执行挂起。如果子进程没有结束或意外终止,它返回0,否则返回子进程的pid。

改变后的程序保存为源文件new_ps_fork2.c,代码如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
  pid_t pid = fork(); 
  int stat = 0; 
  switch(pid) 
  { 
  case -1: 
    perror("fork failed"); 
    exit(1); 
    break; 
  case 0: 
    //这是在子进程中,调用execlp切换为ps进程 
    printf("\n"); 
    execlp("ps", "ps", "au", 0); 
    break; 
  default: 
    //这是在父进程中,等待子进程结束并输出相关提示信息 
    pid = wait(&stat); 
    printf("Child has finished: PID = %d\n", pid); 
    //检查子进程的退出状态 
    if(WIFEXITED(stat)) 
      printf("Child exited with code %d\n", WEXITSTATUS(stat)); 
    else 
      printf("Child terminated abnormally\n"); 
    printf("Parent, ps Done\n"); 
    break; 
  } 
  exit(0); 
} 

输出为:

可以看到这次的输出终于正常了,Parent的输出也在子进程的输出之后。

总结——三种启动新进程方法的比较

首先是最简单的system函数,它需要启动新的shell并在新的shell是执行子进程,所以对环境的依赖较大,而且效率也不高。同时system函数要等待子进程的返回才能执行下面的语句。

exec系统函数是用新的进程来替换原先的进程,效率较高,但是它不会返回到原先的进程,也就是说在exec函数后面的所以代码都不会被执行,除非exec调用失败。然而exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,但需要注意,任何在原进程中已打开的目录流都将在新进程中被关闭。

fork则是用当前的进程来复制出一个新的进程,新进程与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境变量和文件描述符,我们通常根据fork函数的返回值来确定当前的进程是子进程还是父进程,即它并不像exec那样并不返回,而是返回一个pid_t的值用于判断,我们还可以继续执行fork后面的代码。感觉用fork与exec系列函数就能创建很多需的进程。

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


# linux启动进程命令  # Linux启动新进程的三种方法  # Linux启动过程分析和常见错误汇总  # 这是  # 自己的  # 的是  # 将在  # 提示信息  # 不高  # 可以看到  # 后才  # 仍将  # 完全相同  # 是一个  # 也就是说  # 都有  # 子程序  # 在这个  # 出了  # 还可以  # 你可以  # 就能  # 则是 


相关文章: 如何在建站主机中优化服务器配置?  平台云上自助建站如何快速打造专业网站?  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  广东企业建站网站优化与SEO营销核心策略指南  寿县云建站:智能SEO优化与多行业模板快速上线指南  广平建站公司哪家专业可靠?如何选择?  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  营销式网站制作方案,销售哪个网站招聘效果最好?  建站10G流量真的够用吗?如何应对访问高峰?  网站建设制作需要多少钱费用,自己做一个网站要多少钱,模板一般多少钱?  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  建站之星后台密码遗忘?如何快速找回?  专业公司网站制作公司,用什么语言做企业网站比较好?  建站之星上传入口如何快速找到?  如何自定义建站之星网站的导航菜单样式?  如何配置FTP站点权限与安全设置?  清除minerd进程的简单方法  如何在云指建站中生成FTP站点?  网站制作需要会哪些技术,建立一个网站要花费多少?  佛山企业网站制作公司有哪些,沟通100网上服务官网?  如何将凡科建站内容保存为本地文件?  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  高端智能建站公司优选:品牌定制与SEO优化一站式服务  如何快速重置建站主机并恢复默认配置?  攀枝花网站建设,攀枝花营业执照网上怎么年审?  简易网站制作视频教程,使用记事本编写一个简单的网页html文件?  一键制作网站软件下载安装,一键自动采集网页文档制作步骤?  如何制作算命网站,怎么注册算命网站?  C++如何将C风格字符串(char*)转换为std::string?(代码示例)  如何快速搭建自助建站会员专属系统?  如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法  建站之星如何助力网站排名飙升?揭秘高效技巧  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  阿里云网站制作公司,阿里云快速搭建网站好用吗?  建站org新手必看:2024最新搭建流程与模板选择技巧  如何在腾讯云免费申请建站?  如何在万网自助建站中设置域名及备案?  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  如何通过免费商城建站系统源码自定义网站主题与功能?  开源网站制作软件,开源网站什么意思?  开封网站制作公司,网络用语开封是什么意思?  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  建站之星下载版如何获取与安装?  做企业网站制作流程,企业网站制作基本流程有哪些?  如何通过西部建站助手安装IIS服务器?  高端建站三要素:定制模板、企业官网与响应式设计优化  网站app免费制作软件,能免费看各大网站视频的手机app?  深圳网站制作平台,深圳市做网站好的公司有哪些?  如何在腾讯云服务器上快速搭建个人网站?  潍坊网站制作公司有哪些,潍坊哪家招聘网站好? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。