程序中,我们有时需要启动一个新的进程,来完成其他的工作。
下面介绍了三种实现方法,以及这三种方法之间的区别。

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();
}

输出结果:

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

2.exec系列函数-替换进程映像
exec系列函数调用时,启动新进程,替换掉当前进程。即程序不会再返回到原进程,
除非exec调用失败。
exec启动的新进程继承了原进程的许多特性,如在原进程中打开的文件描述符在新进程中仍保持打开。
需要注意的是,在原进程中打开的文件流在新进程中将关闭。原因在于,我们在前面讲过进程间通信的方式,进程之间需要管道才能通信。

原型:

int execl(const char *path,const char *arg0,...,(char*));
int execlp(const char *file,const char *arg0,...,(char*));
int execle(const char *path,const char *arg0,...,(char*),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*));
printf("ps done");
exit();
}

输出结果:

可以看出,调用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 -:
perror("fork failed");
exit();
break;
case :
printf("\n");
execlp("ps","ps","au",);
break;
default:
printf("parent,ps done\n");
break;
}
exit();
}

输出结果:

调用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 = ;
switch(pid)
{
case -:
perror("fork failed");
exit();
break;
case :
printf("\n");
exit();
break;
default:
pid = wait(&stat);
printf("Child has finished:PID=%d\n",pid);
printf("parent,ps done\n");
break;
}
exit();
}

输出结果:

waitpid函数使用示例如下:
process_fork2.c

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

输出结果:

4.启动新进程三种方法的比较
1)system函数最简单,启动shell进程,并在shell进程中执行新的进程。
效率不高,system函数必须等待子进程返回才能接着执行。

2)exec系列函数用新进程替换掉原进程,但不会返回到原进程,除非调用失败。
该函数继承了许多原进程的特性,效率也较高。

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

Linux启动新进程的三种方法的更多相关文章

  1. Linux启动新进程的几种方法汇总

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

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

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

  3. Linux启动新进程的几种方法及比较[转]

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

  4. javascript生成新标签的三种方法

    javascript生成新标签的三种方法:http://www.cnblogs.com/online-link/p/6062423.html

  5. linux清空文件内容的三种方法

    linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...

  6. linux查看磁盘挂载的三种方法

    第一种方法:使用df命令,例如: orientalson:/home # df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda ...

  7. Linux中创建Daemon进程的三种方法

    什么是daemon进程? Unix/Linux中的daemon进程类似于Windows中的后台服务进程,一直在后台运行运行,例如http服务进程nginx,ssh服务进程sshd等.注意,其英文拼写为 ...

  8. VC启动一个新线程的三种方法

    第一种AfxBeginThread() 用AfxBeginThread()函数来创建一个新线程来执行任务,工作者线程的AfxBeginThread的原型如下: CWinThread* AfxBegin ...

  9. linux svn迁移备份的三种方法

    原文:http://www.iitshare.com/linux-svn-migration.html svn备份方式对比分析 一般采用三种方式: 1.svnadmin dump 2.svnadmin ...

随机推荐

  1. Javascript ----字符串(String)中的方法

    涉及字符串时,常用到的几个方法... --------------------------------------------------------------------------------- ...

  2. weblogic服务器的简单使用(一)

    一.前言 现在的公司开发的项目基于的平台是weblogic8.1.5,虽然版本是旧了点,但是用到的功能还是很多的,如JNDI.t3协议.EJB2.0.线程池.连接池.Ant部署.java远程调试. 发 ...

  3. 6、网页制作Dreamweaver(HTML结构--dom操作)

    一.基本语法:数据类型(字符串,小数,整数,布尔,时间) var, var s = "3.14"; var n = parseFloat(s); ; s += 5; var d = ...

  4. 5、网页制作Dreamweaver(JS的初步运用)

    JAVASCRIPT *放在头部也可以读取(最先读取头部) 表单提交时会自动刷新网页,最好关掉 写法: 1.输出 <script> document.write("hello w ...

  5. Centos 6.4 8250/16550 只生成了4个串口

    /********************************************************************* * Centos 6.4 8250/16550 只生成了4 ...

  6. LeetCode Rotate List (链表操作)

    题意: 将链表的后面k个剪出来,拼接到前面,比如 1->2->null 变成2->1->null.数字代表一段的意思. 思路: k有3种可能,k>n,k<n,k=n ...

  7. HDU 1002 A + B Problem II(AC代码)

    #include <stdio.h> #include <string.h> #define MAX 1009 int main() { },b[MAX]={}; ,z=,r= ...

  8. Ubuntu下adb的安装

    1.adb简述: adb全称Android Debug Bridge,安卓调试桥接器.它是Android sdk里的一个工具,用这个工具可以直接操作管理android模拟器或者真实的andriod设备 ...

  9. Jquery attr判断服务器单选按钮失败

    在项目中用 jquey的attr方法获取服务器控件的单选按钮checked属性会不成功, 单选选中改变,用attr获取不到最新的值,但是用 $("#rdbPartySend").i ...

  10. haar-like特征(转载)

    浅析人脸检测之Haar分类器方法  [补充] 这是我时隔差不多两年后, 回来编辑这篇文章加的这段补充, 说实话看到这么多评论很是惊讶, 有很多评论不是我不想回复, 真的是时间久了, 很多细节我都忘记了 ...