网站设计需要什么软件,室内装饰装修施工图集,如何做全网营销推广,解释网站为什么这样做1 什么是创建新进程(夺舍) 在前面文章中#xff0c;我们学习了fork()函数用来创建子进程。 子进程是父进程的副本#xff0c;复制父进程除代码段以外的其他数据#xff0c;代码段数据和父进程共享。 子进程的PID与父进程不同#xff1a; 而创建新进程则不同。 与fork()不同…1 什么是创建新进程(夺舍) 在前面文章中我们学习了fork()函数用来创建子进程。 子进程是父进程的副本复制父进程除代码段以外的其他数据代码段数据和父进程共享。 子进程的PID与父进程不同 而创建新进程则不同。 与fork()不同exec函数族不是创建调用进程的子进程而是创建一个新的进程去掉调用进程自身。 新进程会用自己的全部地址空间覆盖调用进程的地址空间。 新进程的PID与调用进程相同子进程变身后父子关系不变 2 创建新进程(夺舍) exec不是一个函数而是一堆函数(6个)称为exec函数族。它们的功能是相同的用法也相近只是参数的形式和数量略有不同。建议只熟练用第1个即可。 #include unistd.h 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[]); 功能让新进程取代原本的旧进程 path可执行文件的路径 arg命令行参数 ...不定长参数(可变长参数)就像printf() envp旧进程为新进程指定的环境变量不指定则从调用进程复制。 变相地在向新进程传递数据 llist新进程的命令行参数以字符指针列表(const char* arg, ...)的形式传入列表以空 指针结束别忘了写NULL。 vvector新进程的命令行参数以字符指针数组(char* const argv[])的形式传入数组以 空指针结束。 ppath若第一个参数中不包含/完整路径则将其视为文件名并根据PATH环境变 量搜索该文件。 eenvironment新进程的环境变量以字符指针数组(char* const envp[])的形式传入 数组以空指针结束不指定环境变量则从调用进程复制。 其实6个exec函数只有execve是真正的系统调用其它5个是对evecve的简单包装 调用exec函数不仅改变调用进程的地址空间和进程映像调用进程的一些属性也发生了变化归零、默认、失效 -任何处于阻塞状态的信号都会丢失 -被设置为捕获的信号会还原为默认操作 -有关线程属性的设置会还原为缺省值 -有关进程的统计信息会复位 -与进程内存相关的任何数据都会丢失包括内存映射文件局部变量等 -标准库在用户空间维护的一切数据结构如通过atexit或on_exit函数注册的退出处理函数 都会丢失 但有些属性会被新进程继承下来如PIDPPID实际用户ID实际组ID优先级文件描述符等。 注意如果新进程创建成功exec函数是不会返回的因为成功的exec调用会以跳转到新进程的入口地址作为结束而刚刚运行的代码是不会存在于新进程的地址空间中的旧进程已死没得返回新进程没调用也就返不给新进程。但如果进程创建失败exec函数会返回-1。
//new.c 变身的目标
#includestdio.h
#includeunistd.hint main(int argc,char* argv[],char* envp[]){printf(PID : %d\n,getpid());printf(命令行参数:\n);for(char** pp argv;*pp;pp){printf(%s\n,*pp);}printf(环境变量:\n);for(char** pp envp;*pp;pp){printf(%s\n,*pp);}printf(---------------------\n);return 0;
}
//编译执行为new作为变身的目标
//exec.c 创建新进程bash的子进程exec变身成new进程
#includestdio.h
#includeunistd.hint main(void){printf(%d进程:我要变身了\n,getpid());/*if(execl(./new,new,hello,123,NULL) -1){ //第一个参数已定位故第二perror(execl); //个new无需再./return -1;}*//*if(execl(/bin/ls,ls,-i,-a,-l,NULL) -1){ //变身成ls命令perror(execl); //命令的本质就是可执行程序return -1; }*//*if(execlp(lsSSSS,ls,-a,-i,NULL) -1){ //报错perror(execlp);return -1;}*///演示execve()定义2个char* []//指定新进程的环境变量变相在新旧进程间传递数据char* envp[] {NAMElaozhang,AGE18,FOODguobaorou,NULL};/*if(execle(./new,new,hello,123,NULL,envp) -1){perror(execle);return -1;}*/char* argv[] {new,hello,123,NULL};if(execve(./new,argv,envp) -1){perror(execve);return -1;}printf(%d进程:变身完成了\n,getpid());//不会执行因为前面已经进入new进程了return 0; //本进程已被抛弃代码自然不被执行
}//编译执行 调用exec函数固然可以创建出新的进程但是新进程会取代原来的进程。如果既想创建新的进程同时又希望原来的进程继续存在 则可以考虑fork() exec()模式即在fork产生的子进程里调用exec函数新进程取代了子进程但父进程依然存在 //forkexec.c fork() exec()模式
#includestdio.h
#includeunistd.h
#includesys/wait.hint main(void){//创建子进程pid_t pid fork();if(pid -1){perror(fork);return -1;}//子进程代码,exec变身if(pid 0){if(execl(./new,new,hello,123,NULL) -1){perror(execl);return -1;}//return 0; //可以注释掉因为已变身成new进程了这里压根不执行} //即使变身失败也return -1; 了//父进程代码,收尸int s;//用来输出子进程的终止状态if(waitpid(-1,s,0) -1){ //-1任意PID0阻塞perror(waitpid);return -1;}if(WIFEXITED(s)){printf(正常终止:%d\n,WEXITSTATUS(s));}else{printf(异常终止:%d\n,WTERMSIG(s));}//创建第二个子进程pid fork();if(pid -1){perror(fork);return -1;}//子进程代码if(pid 0){if(execl(/bin/ls,ls,-i,-l,NULL) -1){perror(execl);return -1;}//return 0;}//父进程代码if(waitpid(-1,s,0) -1){perror(waitpid);return -1;}if(WIFEXITED(s)){ //宏判断进程死因printf(正常终止:%d\n,WEXITSTATUS(s));}else{printf(异常终止:%d\n,WTERMSIG(s));}return 0;
}
//编译执行
3 system() 最优 system() fork() exec () waitpid() 使用system()函数而不用vfork() exec ()的好处是system函数针对各种错误和信号都做了必要的处理而且system是标准库函数可跨平台使用各种报错措施也完备。 #include stdlib.h int system(const char* command); 功能执行shell命令 commandshell命令行字符串 返回值成功返回command进程的终止状态失败返回-1 system()函数执行command参数所表示的命令行并返回命令进程的终止状态。 若command参数取NULL返回非0表示shell可用返回0表示shell不可用。 在system()函数内部调用了vfork() exec () 和waitpid()等函数 -如果调用vfork()或waitpid()函数出错则返回-1 -如果调用exec()函数出错则在子进程中执行exit(127) -如果都成功则返回command进程的终止状态(由waitpid()的status参数获得)
//system.c system()函数演示
#includestdio.h
#includestdlib.h //system()是标准库函数
#includesys/wait.hint main(void){int s system(./new hello 123); //就像在命令行输入if(s -1){ //system()失败perror(system);return -1;}if(WIFSIGNALED(s)){ //宏1printf(异常终止:%d\n,WTERMSIG(s)); //sytem()成功./new失败}else{printf(正常终止:%d\n,WEXITSTATUS(s));}//创建第2个新进程s system(ls -i -l --colorauto); //试试不加--if(s -1){ //.bashrc中alias lsls --colorautu后perror(system); //只有bash终端自带效果但程序中要手敲return -1;}if(WIFEXITED(s)){ //宏2等效滴printf(正常终止:%d\n,WEXITSTATUS(s));}else{printf(异常终止:%d\n,WTERMSIG(s));}return 0;
}
//编译执行 vfork()生成的子进程不会复制数据而是共用父进程的数据省时省力至今用于system()底层。运行时子进程优先用父进程阻塞子进程结束后父进程才继续运行。 近来写时复制的发明vfork()用得少了可不深究更多用fork()即可。
3.1 电子表 尝试用system()写个电子钟表显示时分秒每秒更新。