重庆邮电大学移通学院毕业设计(论文) 第2章 Linux多进程编程
i am the child process 3 i am the parent process 1 i am the child process 4 i am the parent process 2 i am the child process 5 i am the parent process 3 i am the child process 6 i am the parent process 4 i am the parent process 5 i am the parent process 6 i am the parent process 7 i am the parent process 8 i am the parent process 9 代码关键部分解释:
首先,定义子进程的PID,代码为pid_t pid; 再次,获得子进程PID,代码pid=fork(); 第三,对于main函数中的if语句
if(pid<0) {
/*如果pid<0子进程创建错误*/ }
else if(pid==0) {
/*当pid==0时,此时else if 中的语句就是子进程代码*/ } else {
/*父进程代码*/ }
这里值得注意的是如果pid不小于0,则else if,和else中的代码是同时运行的,这和一般的if-else if-else语句同。
这里还需要注意的是在子进程函数中有个exit()系统调用。当子进程运行到exit()时,子进程退出。而父进程不受影响。
2.1.2 fork()与vfork()区别[3]
fork()与 vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点
16
重庆邮电大学移通学院毕业设计(论文) 第2章 Linux多进程编程
区别:
1.fork():子进程拷贝父进程的数据段,堆栈段 vfork():子进程与父进程共享数据段 2.fork()父子进程的执行次序不确定
vfork 保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的,在它调用 exec或exit之后父进程才可能被调度运行。
3.vfork 保证子进程先运行,在她调用 exec 或 exit 之后父进程才可能被调度运行。如果在 调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
2.2 exec函数族[1][2][3][15]
2.2.1简介
说是exec系统调用,实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:
#include
int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
与一般情况不同,exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样。看上去还是旧的躯壳,却已经注入了新的灵魂。
17
重庆邮电大学移通学院毕业设计(论文) 第2章 Linux多进程编程
只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。
现在我们应该明白了,Linux下是如何执行新程序的,每当有进程认为自己不能为系统和拥护做出任何贡献了,他就可以发挥最后一点余热,调用任何一个exec,让自己以新的面貌重生;或者,更普遍的情况是,如果一个进程想执行另一个程序,它就可以fork出一个新进程,然后调用任何一个exec,这样看起来就好像通过执行应用程序而产生了一个新进程一样。
2.2.2 exec()函数族解析[3]
2.2.2.1 execl(执行文件)
相关函数
fork,execle,execlp,execv,execve,execvp 表头文件
#include
int execl(const char * path,const char * arg,....); 函数说明
execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]??,最后一个参数必须用空指针(NULL)作结束。返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。 范例
#include
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char * )0); } 执行
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
2.2.2.2 execlp(从PATH 环境变量中查找文件并执)
相关函数
fork,execl,execle,execv,execve,execvp 表头文件
#include
int execlp(const char * file,const char * arg,??); 函数说明
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便
18
重庆邮电大学移通学院毕业设计(论文) 第2章 Linux多进程编程
执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]??,最后一个参数必须用空指针(NULL)作结束。 返回值
如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。错误代码
参考execve()。 范例
/* 执行ls -al /etc/passwd execlp()会依PATH 变量中的/bin找到/bin/ls */ #include
execlp(“ls”,”ls”,”-al”,”/etc/passwd”,(char *)0); } 执行
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
2.2.23 execv(执行文件)
相关函数
fork,execl,execle,execlp,execve,execvp 表头文件
#include
int execv (const char * path, char * const argv[ ]); 函数说明
execv()用来执行参数path字符串所代表的文件路径,与execl()不同的地方在于execve()只需两个参数,第二个参数利用数组指针来传递给执行文件。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。 错误代码
请参考execve()。 范例
/* 执行/bin/ls -al /etc/passwd */ #include
char * argv[ ]={“ls”,”-al”,”/etc/passwd”,(char*) }; execv(“/bin/ls”,argv); } 执行
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
2.2.2.4 execve(执行文件)
相关函数
fork,execl,execle,execlp,execv,execvp
19
重庆邮电大学移通学院毕业设计(论文) 第2章 Linux多进程编程
表头文件
#include
int execve(const char * filename,char * const argv[ ],char * const envp[ ]); 函数说明
execve()用来执行参数filename字符串所代表的文件路径,第二个参数系利用数组指针来传递给执行文件,argv要传递给程序的完整参数列表,包括argv[0],它一般是执行程序的名字;最后一个参数则为传递给执行文件的新环境变量数组。返回值如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。 错误代码 EACCES
1. 欲执行的文件不具有用户可执行的权限。
2. 欲执行的文件所属的文件系统是以noexec 方式挂上。 3.欲执行的文件或script翻译器非一般文件。 EPERM
1.进程处于被追踪模式,执行者并不具有root权限,欲执行的文件具有SUID 或SGID 位
2.欲执行的文件所属的文件系统是以nosuid方式挂上,欲执行的文件具有SUID 或SGID 位元,但执行者并不具有root权限 #include
char* args[] = { \
if ( -1 == (execve(\ { perror( \ exit( EXIT_FAILURE); }
puts( \ exit( EXIT_SUCCESS ); }
[root@localhost src]# gcc execve.c [root@localhost src]# ./a.out
a.out child_fork.c execve.c fork.c getpid.c
20