嵌入式LinuxC编程之进程控制(二)
来源:互联网 发布:在线教学软件 编辑:程序博客网 时间:2024/05/16 11:33
承接上一节所写内容,首先通过fork()和vfork()函数创建子进程,子进程与父进程执行的代码是相同的。通常创建了一个进程,目的是为了执行与父进程不同的操作,实现不用的功能,有错引进了exec()函数族。
一、exec()函数族:
1、有六个exec开头的函数组成
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,const char *argv[]);
int execve(const char *path,const char *argv[],char *const envp[]);
int execvp(const char *file,const char *argv[]);
这些函数都定义在函数库中,在使用前需包含头文件<sys/types.h>和<unistd.h>,并且在预定义时定义一个外部的全局变量 extern char **environ;
其作用就是,定义完此命令,可在当前目录执行系统程序,如同执行vim一样。
exec()函数族中的函数,都实现对子进程的数据段、代码段和堆栈段进行替换的功能,如果调用成功,则加载新程序,没有返回值。如果出错返回-1.
2、如何记住exec函数的区别:
(1) 函数名中带有p:代表文件的绝对路径(或称相对路径),当函数中带有p时可以不用书写文件的相对路径,只写出文件名即可。
(2) 函数名中带有l:表示将新程序的每个命令行参数都当作一个参数传给它,参数个数可变,并且最后要输入一个NULL参数表示参数输入结束。
(3) 函数名中带有v:表示该类函数支持使用参数数组,数组中的最后一个指针也要输入NULL参数作为结束标志,类似于main()函数的形参argv[].
3、其他exec函数
一、exec()函数族:
1、有六个exec开头的函数组成
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,const char *argv[]);
int execve(const char *path,const char *argv[],char *const envp[]);
int execvp(const char *file,const char *argv[]);
这些函数都定义在函数库中,在使用前需包含头文件<sys/types.h>和<unistd.h>,并且在预定义时定义一个外部的全局变量 extern char **environ;
其作用就是,定义完此命令,可在当前目录执行系统程序,如同执行vim一样。
exec()函数族中的函数,都实现对子进程的数据段、代码段和堆栈段进行替换的功能,如果调用成功,则加载新程序,没有返回值。如果出错返回-1.
2、如何记住exec函数的区别:
(1) 函数名中带有p:代表文件的绝对路径(或称相对路径),当函数中带有p时可以不用书写文件的相对路径,只写出文件名即可。
(2) 函数名中带有l:表示将新程序的每个命令行参数都当作一个参数传给它,参数个数可变,并且最后要输入一个NULL参数表示参数输入结束。
(3) 函数名中带有v:表示该类函数支持使用参数数组,数组中的最后一个指针也要输入NULL参数作为结束标志,类似于main()函数的形参argv[].
(4) 函数名以e结尾:该类函数表示可以将一份新的函数变量表传给它。
示例:execve函数//new2.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(void){puts("welcome to mrsoft");return 0;}//execve.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(int argc,char* argv[]){execve("new",argv,environ);//此处调用可执行文件new,也就是new2.c编译后的执行文件//此时进程中的代码段、数据段和进程段都进行了修改,使得新创建的进程只执行新加载的这个程序的代码puts("正常情况下无法输出此信息");}执行结果:welcome to mrsoft!//修改后的execve.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(int argc,char* argv[]){pid_t pid;if((pid=fork())<0)printf("create child process failed!\n");else if(pid==0) execve("new",argv,environ);else puts("正常情况下输出此信息!\n");}//运行结果:正常情况下输出此信息!//welcome to mrsoft!//再次修改execve.c//在那个进程中调用,PID还是那个进程的#include<stdio.h>#include<unistd.h>#include<sys/types.h>int gvar=2;//全局变量int main(void){pid_t pid;int var=5;//局部变量printf("process id:%ld\n",(long)getpid());//输出父进程的PIDprintf("gvar=%d var=%d\n",gvar,var);if((pid=fork())<0)//创建子进程失败{perror("error!");return 1;}else if(pid==0)//如果在子进程中执行以下程序{gvar--;var++;//输出子进程的PID和修改后的变量值printf("the child process id:%ld,gvar=%d var=%d\n",(long)getpid(),gvar,var);return 0;}else{ //输出父进程的PID以及变量值printf("the parent process id:%ld,gvar=%d var=%d\n",(long)getpid(),gvar,var);execve("new",argv,environ);return 0;}}//修改后的new.c#include<stdio.h>#include<unistd.h>#include<sys/types.h>extern char **environ;int main(void){puts("welcome to mrsoft");printf("newPID=%ld\n",(long)getpid());return 0;}/*运行结果:process id:4043 gvar=2 var=5 the parent process id:4043,gvar=2,var=5 the child process id:4044,gvar=1,var=6 welcome to mrsoft newPID=4043*/
3、其他exec函数
#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>int main(int argc, char *argv[]){ //以NULL结尾的字符串数组的指针,适合包含v的exec函数参数 char *arg[] = {"ls", "-a", NULL}; /** * 创建子进程并调用函数execl * execl 中希望接收以逗号分隔的参数列表,并以NULL指针为结束标志 * 包含有 l ① 说明需要在另加上可执行程序作为第二个参数 当然可以加第三、四个等 待参数 * ② 注意不能够外加参数,因为它不能添加参数argv,因此不能再加参数 * 不包含l时参数就不用以NULL结尾 */ if( fork() == 0 ) { // in clild printf( "1------------execl------------\n" ); if( execl( "/bin/ls", "ls","-a", NULL ) == -1 ) { perror( "execl error " ); exit(1); } } /** *创建子进程并调用函数execv,包含v的特点 *execv中希望接收一个以NULL结尾的字符串数组的指针, *也可以说可以通过外加参数比如:./a -l 等价于 ls -l */ if( fork() == 0 ) { // in child printf("2------------execv------------\n");//注意:execv( "/bin/ls","-l",arg) 是错误的写法,其他参数应另外添加 if( execv( "/bin/ls",arg) < 0) { perror("execv error "); exit(1); } } /** *创建子进程并调用 execlp *execlp中与execl类似,多了个p *l希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志 *p是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件 */ if( fork() == 0 ) { printf("3------------execlp------------\n"); if( execlp( "ls", "ls", "-a", NULL ) < 0 ) { perror( "execlp error " ); exit(1); } } /** *创建子里程并调用execvp *v 望接收到一个以NULL结尾的字符串数组的指针 *p 是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件 */ if( fork() == 0 ) { printf("4------------execvp------------\n"); if( execvp( "ls", arg ) < 0 ) { perror( "execvp error " ); exit( 1 ); } } /** *创建子进程并调用execle *l 希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志 *e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境 */ if( fork() == 0 ) { printf("5------------execle------------\n"); if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 ) { perror("execle error "); exit(1); } } /** *创建子进程并调用execve * v 希望接收到一个以NULL结尾的字符串数组的指针 * e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境 *在运行时另加参数,如:./a -l 如同执行:ls -l */ if( fork() == 0 ) { printf("6------------execve-----------\n"); if( execve( "/bin/ls", arg, NULL ) == 0)//必须加上路径,绝对路径或相对路径否则找不到要执行的程序 { perror("execve error "); exit(1); } } return EXIT_SUCCESS;}
0 0
- 嵌入式LinuxC编程之进程控制(二)
- 嵌入式LinuxC编程之进程控制(一)
- 嵌入式LinuxC编程之进程控制(三)
- 学习linuxC编程实战-----linux进程控制
- LinuxC系统编程——进程控制(1)
- LinuxC之进程
- 高质量嵌入式Linuxc编程
- linuxC编程之文件操作与进程初步
- Linuxc编程之信号
- 系统编程之进程控制编程(二)
- 进程控制(二)进程控制编程
- linux系统编程之进程(二):进程生命周期与PCB(进程控制块)
- linux系统编程之进程(二):进程生命周期与PCB(进程控制块)
- linux系统编程之进程(二):进程生命周期与PCB(进程控制块)
- LinuxC高级编程——进程
- linuxC系统编程——进程管理
- 系统编程之进程控制
- LinuxC编程一站式学习笔记(二)
- [LeetCode] Count Numbers with Unique Digits 计算各位数值不同的数的个数
- 人的四种认知状态
- EOJ 3260 袋鼠妈妈找孩子 题解
- 基于EEG信号的情绪分析数据库DEAP论文调研
- 4-6 求单链表结点的阶乘和 (15分)
- 嵌入式LinuxC编程之进程控制(二)
- php 中时间函数date及常用的时间计算
- 一天搞定CSS(扩展):CSS Hack
- windows 下安装 NSClient++
- Intellij IDEA 创建GUI界面
- 初识.net界面程序(9)--LINQ To XML
- 编译ijkplayer-android源码
- C#匿名方法之循环注册问题
- 获取wifi密码的方式