进程控制开发之:Linux进程控制编程
(4)函数使用注意点。
fork()函数使用一次就创建一个进程,所以若把fork()函数放在了ifelse判断语句中则要小心,不能多次使用fork()函数。
小知识 | 由于fork()完整地复制了父进程的整个地址空间,因此执行速度是比较慢的。为了加快fork()的执行速度,有些UNIX系统设计者创建了vfork()。vfork()也能创建新进程,但它不产生父进程的副本。它是通过允许父子进程可访问相同物理内存从而伪装了对进程地址空间的真实拷贝,当子进程需要改变内存中数据时才复制父进程。这就是著名的“写操作时复制”(copy-on-write)技术。 现在很多嵌入式Linux系统的fork()函数调用都采用vfork()函数的实现方式,实际上uClinux所有的多进程管理都通过vfork()来实现。 |
2.exec函数族
(1)exec函数族说明。
fork()函数是用于创建一个子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的进程如何执行呢?这个exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。
在Linux中使用exec函数族主要有两种情况。
n 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。
n 如果一个进程想执行另一个程序,那么它就可以调用fork()函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。
(2)exec函数族语法。
实际上,在Linux中并没有exec()函数,而是有6个以exec开头的函数,它们之间语法有细微差别,本书在下面会详细讲解。
下表7.3列举了exec函数族的6个成员函数的语法。
表7.3 exec函数族成员函数语法
所需头文件 | #includeunistd.h> |
函数原型 | intexecl(constchar*path,constchar*arg,...) |
intexecv(constchar*path,char*constargv[]) | |
intexecle(constchar*path,constchar*arg,...,char*constenvp[]) | |
intexecve(constchar*path,char*constargv[],char*constenvp[]) | |
intexeclp(constchar*file,constchar*arg,...) | |
intexecvp(constchar*file,char*constargv[]) | |
函数返回值 | -1:出错 |
这6个函数在函数名和使用语法的规则上都有细微的区别,下面就可执行文件查找方式、参数表传递方式及环境变量这几个方面进行比较。
n 查找方式。
读者可以注意到,表7.3中的前4个函数的查找方式都是完整的文件目录路径,而最后2个函数(也就是以p结尾的两个函数)可以只给出文件名,系统就会自动按照环境变量“$PATH”所指定的路径进行查找。
n 参数传递方式。
exec函数族的参数传递有两种方式:一种是逐个列举的方式,而另一种则是将所有参数整体构造指针数组传递。
在这里是以函数名的第5位字母来区分的,字母为“l”(list)的表示逐个列举参数的方式,其语法为char*arg;字母为“v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为*constargv[]。读者可以观察execl()、execle()、execlp()的语法与execv()、execve()、execvp()的区别。它们具体的用法在后面的实例讲解中会具体说明。
这里的参数实际上就是用户在使用这个可执行文件时所需的全部命令选项字符串(包括该可执行程序命令本身)。要注意的是,这些参数必须以NULL表示结束,如果使用逐个列举方式,那么要把它强制转化成一个字符指针,否则exec将会把它解释为一个整型参数,如果一个整型数的长度char*的长度不同,那么exec函数就会报错。
n 环境变量。
exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里以“e”(environment)结尾的两个函数execle()和execve()就可以在envp[]中指定当前进程所使用的环境变量。
表7.4是对这4个函数中函数名和对应语法的小结,主要指出了函数名中每一位所表明的含义,希望读者结合此表加以记忆。
表7.4 exec函数名对应含义
前4位 | 统一为:exec | |
第5位 | l:参数传递为逐个列举方式 | execl、execle、execlp |
v:参数传递为构造指针数组方式 | execv、execve、execvp | |
第6位 | e:可传递新进程环境变量 | execle、execve |
p:可执行文件查找方式为文件名 | execlp、execvp |
(3)exec使用实例。
下面的第一个示例说明了如何使用文件名的方式来查找可执行文件,同时使用参数列表的方式。这里用的函数是execlp()。
/*execlp.c*/
#includeunistd.h>
#includestdio.h>
#includestdlib.h>
intmain()
{
if(fork()==0)
{
/*调用execlp()函数,这里相当于调用了ps-ef命令*/
if((ret=execlp(ps,ps,-ef,NULL))0)
{
printf(Execlperrorn);
}
}
}
在该程序中,首先使用fork()函数创建一个子进程,然后在子进程里使用execlp()函数。读者可以看到,这里的参数列表列出了在shell中使用的命令名和选项。并且当使用文件名进行查找时,系统会在默认的环境变量PATH中寻找该可执行文件。读者可将编译后的结果下载到目标板上,运行结果如下所示:
$./execlp
PIDTTYUidSizeStateCommand
1root1832Sinit
2root0S[keventd]
3root0S[ksoftirqd_CPU0]
4root0S[kswapd]
5root0S[bdflush]
6root0S[kupdated]
7root0S[mtdblockd]
8root0S[khubd]
35root2104S/bin/bash/usr/etc/rc.local
36root2324S/bin/bash
41root1364S/sbin/inetd
53root14260S/Qtopia/qtopia-free-1.7.0/bin/qpe-qws
54root11672Squicklauncher
65root0S[usb-storage-0]
66root0S[scsi_eh_0]
83root2020Rps-ef
$env
……
PATH=/Qtopia/qtopia-free-1.7.0/bin:/usr/bin:/bin:/usr/sbin:/sbin
……
linux操作系统文章专题:linux操作系统详解(linux不再难懂)
评论