Linux启动新进程的三种方法
发布时间 - 2026-01-11 00:52:35 点击率:次程序中,我们有时需要启动一个新的进程,来完成其他的工作。

下面介绍了三种实现方法,以及这三种方法之间的区别。
1.system函数-调用shell进程,开启新进程
system函数,是通过启动shell进程,然后执行shell命令进程。
原型:
int system(const char *string);
string:shell命令字符串
返回值:成功返回命令退出码,无法启动shell,返回127错误码,其他错误,返回-1。
代码示例如下:
process_system.c
#include<stdlib.h>
#include<stdio.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
#include<stdio.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
#include<stdio.h>
#include<sys/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
#include<wait.h>
#include<stdio.h>
#include<sys/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
#include<wait.h>
#include<stdio.h>
#include<sys/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
# 启动进程
# linux启动进程命令
# Linux启动新进程的几种方法及比较
# Linux启动过程分析和常见错误汇总
# 的是
# 自己的
# 返回值
# 不高
# 种方法
# 需要注意
# 信号量
# 其他的
# 继承了
# 并在
# 较高
# 数据结构
# 三种
# 任何一个
# 可以看出
# 四种
# 在前面
# 会再
# 会将
# 最简单
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】
如何使用 jQuery 正确渲染 Instagram 风格的标签列表
Laravel如何使用查询构建器?(Query Builder高级用法)
高性能网站服务器配置指南:安全稳定与高效建站核心方案
Laravel如何配置Horizon来管理队列?(安装和使用)
浅述节点的创建及常见功能的实现
如何用已有域名快速搭建网站?
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】
JS经典正则表达式笔试题汇总
如何用西部建站助手快速创建专业网站?
韩国服务器如何优化跨境访问实现高效连接?
JavaScript Ajax实现异步通信
HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】
如何在建站之星绑定自定义域名?
如何快速搭建个人网站并优化SEO?
高防服务器:AI智能防御DDoS攻击与数据安全保障
如何在阿里云高效完成企业建站全流程?
如何在局域网内绑定自建网站域名?
Android仿QQ列表左滑删除操作
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
昵图网官网入口 昵图网素材平台官方入口
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
如何确保FTP站点访问权限与数据传输安全?
Laravel如何优化应用性能?(缓存和优化命令)
如何在云主机上快速搭建网站?
Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】
如何挑选最适合建站的高性能VPS主机?
深圳网站制作的公司有哪些,dido官方网站?
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
java中使用zxing批量生成二维码立牌
大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?
Laravel用户认证怎么做_Laravel Breeze脚手架快速实现登录注册功能
如何用PHP快速搭建高效网站?分步指南
Python3.6正式版新特性预览
Laravel如何为API生成Swagger或OpenAPI文档
laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法
在centOS 7安装mysql 5.7的详细教程
Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理
如何用IIS7快速搭建并优化网站站点?
如何在建站之星网店版论坛获取技术支持?
详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点
Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
教你用AI润色文章,让你的文字表达更专业
如何用AWS免费套餐快速搭建高效网站?
如何在云服务器上快速搭建个人网站?
如何在云主机上快速搭建多站点网站?
Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例
laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法

