exec函数和system()函数
exec函数和system()函数
进程控制
关于这一章基本是按照书上的知识写的, 虽然不明白查了一些资料, 但是后面明白了觉得还是书上写的好, 也就没有自己太多的想法,只是整理加深印象而已, 如果只是寻找理解的朋友, 这就不是很有用了。
进程掉用exec时, 该进程执行的程序会完全替换成新的程序, 也就是直接从main函数开始重新执行。
exec调用不会创建新的进程, 所以也就不会有新的ID产生。
exec只是用磁盘上新程序替换了现在进程的堆栈, 数据段, 正文段.
fork()创造新的进程, exec创造新的程序, exit和wait返回进程终止和等待终止.
进程中每个打开文件描述符都应该在exec执行前进行关闭, 否则执行exec后这些文件描述符将继续打开而不会关闭
我觉得着这函数还是后面要用, 自己也想加深一下理解, 所以写了出来, 不想看闲麻烦的也可以跳过
| #include < unistd.h> |
|---|
| int execl(const char *pathname, const char arg0, … /* (char) 0 */) |
| int execv(const char *pathname, char *const argv[]); |
| int execle(const char *pathname, const char *arg0, … /* (char *) 0, char *const envp[] */ |
| int execve(const char *pathname, char *const argv[], char *const envp[]); |
| int execlp(const char *filename, const char *arg0, … /* (char *)0 */); |
| int execvp(const char *filename, char *const argv[]); |
| int fexecve(int fd, char *const argv[], char *const envp[]); |
- 错误, 返回 -1; 成功, 不返回
- 前四个取路径名为参数。execlp()和execvp()取文件描述符为参数, 但是如果filename包含 “/”就取路径名, 否则按照PATH环境变量搜寻可执行文件(一般是shell文件)。
- execl(), execle(), execlp()函数最后参数以 “NULL”结尾。
/*************************************************************************> File Name: environ_打印环境表参数.cpp> Author: Function_Dou> Mail:> Created Time: 2018年02月01日 星期四 21时58分25秒************************************************************************/#include <stdio.h>#include "apue.h"int main(int argc, char *argv[]){int i;char **ptr;extern char **environ;for(i = 0; i < argc; i++)printf("argv[%d] : %s\n", i, environ[i]);// 输出所有的环境变量for(ptr = environ; *ptr != 0; ptr++)printf("%s\n", *ptr);exit(0);}
解释器
解释器就是#! 后面可执行的程序。
对于解释器,exec族函数是这样做的(以execl为例),如果path是指向了一个脚本,脚本的第一行以#!开头,则:以#!后面的字符串为命令,后面加上execl参数列表中指定的参数列表,这样形成了新的程序执行。
如何理解解释器呢, 我看了些资料按照自己的思路整理了下。
先创建了一个cpp文件
/*************************************************************************> File Name: jieshiqi.cpp> Author: Function_Dou> Mail:> Created Time: 2018年02月01日 星期四 22时18分59秒************************************************************************/#include <stdio.h>int main(int argc, char *argv[]){int i;for(i = 0; i < argc; i++)printf("argv[%d] : %s\n", i, argv[i]);return 0;}
又写了一个脚本
#!/home/RPZ/Code/Cc++/Process/a.out Function# 这是我jieshiqi.cpp生成的a.out的位置
当然权限要设置够
-rwxr-xr-x. 1 root root 44 2月 1 22:21 JSQ
最后运行JSQ, 结果就出来了
[root@192 Process]# ./JSQargv[0] : /home/RPZ/Code/Cc++/Process/a.outargv[1] : Functionargv[2] : ./JSQ
- 开始时讲到的,exec族函数的处理是把#!后面的字符串为命令,后面加上execl参数列表中指定的参数列表,这样形成了新的程序执行
- execl把命令的结果是这样执行的/home/RPZ/Code/Cc++/Process/JSQ的内容是#!/home/RPZ/Code/Cc++/Process/a.out Function,则#!后面的字符串”/home/RPZ/Code/Cc++/Process/a.out”加上命令参数列表:”Function” “自身的文件./JSQ(也就是exec族传进来的第一参数)” 就形成了新的程序行:/home/RPZ/Code/Cc++/Process/a.out Function ./JSQ
还是不太清楚可以看下面的地址里讲的, 只是排面有点不好看而已
http://blog.youkuaiyun.com/yylklshmyt20090217/article/details/4217616
system() 函数
#include <stdlib.h>int system("cosnt char *cmdstring);
- 关于返回值
system()在实现中调用了fork(), waitpid(), exec()函数
1. fork失败或者waitpid返回除EINTR之外的出错, 则system返回 -1, 并设置errno已指示错误类型
2. exec失败, 返回值如同shell执行exit一样
3. 3个函数都成功了, system返回值是shell的终止状态
/*************************************************************************> File Name: system_函数的实现.cpp> Author: Function_Dou> Mail:> Created Time: 2018年02月01日 星期四 22时43分18秒************************************************************************/#include <stdio.h>#include <sys/wait.h>#include <errno.h>#include <unistd.h>#include "apue.h"int system(const char *cmdstring){pid_t pid;int status;if(cmdstring == NULL)return 1;if((pid = fork()) < 0)status = -1;else if(pid == 0){// shell 的-c选项是告诉shell程序读取下一个命令行参数(这里是cmdstring)作为命令输入(而不是从标准输入或者指定文件读命令);execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);_exit(0);}elsewhile(waitpid(pid, &status, 0) < 0)if(errno != EINTR){status = -1;break;}return status;}voidpr_exit(int status){if (WIFEXITED(status))printf("normal termination, exit status = %d\n",WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status),#ifdef WCOREDUMPWCOREDUMP(status) ? " (core file generated)" : ""#else""#endif);else if (WIFSTOPPED(status))printf("child stopped, signal number = %d\n", WSTOPSIG(status));}int main(void){int status;if((status = system("date")) < 0)err_sys("system() error");pr_exit(status);if((status = system("no file")) < 0)err_sys("system() error");pr_exit(status);if((status = system("who; exit 44")) < 0)err_sys("system() error");pr_exit(status);exit(0);}/* 样列*[root@192 Process]# ./a.out2018年 02月 01日 星期四 22:57:00 CSTnormal termination, exit status = 0sh: no: 未找到命令normal termination, exit status = 127root :2 2018-02-01 14:30 (:2)root pts/0 2018-02-01 20:58 (:2)root pts/1 2018-02-01 21:40 (:2)root pts/2 2018-02-01 21:56 (:2)normal termination, exit status = 44*/
如果在调用system就已经有了子进程, 那么就将出问题.
nice()值的效果
这里具体只写了一个程序, 将书上的那个程序进行了解释
/*************************************************************************> File Name: nice_调度.cpp> Author: Function_Dou> Mail:> Created Time: 2018年02月02日 星期五 11时53分18秒*************************** timeval ***********************************struct timeval{long tv_sec; //秒long tv_usec; //微秒};struct timezone{int tz_minuteswest; //和Greenwich 时间差了多少分钟int tz_dsttime; //日光节约时间的状态};*************************** gettimeofday *******************************int gettimeofday (struct timeval * tv, struct timezone * tz);gettimeofday 会把目前的时间放入tv, 结构中, 当地时区的信息则放入tz结构中.返回值:成功则返回0,失败返回-1,错误代码存于errno。*************************** nice **************************************int nice(int inc);nice()用来改变进程的进程执行优先顺序. 参数inc 数值越大则优先顺序排在越后面, 即表示进程执行会越慢. 只有超级用户才能使用负的inc 值, 代表优先顺序排在前面, 进程执行会较快.如果执行成功则返回0, 否则返回-1, 失败原因存于errno 中.**************************** strtol ***********************************long int strtol (const char* str, char** endptr, int base);strtol() 函数用来将字符串转换为长整型数(long)str 为要转换的字符串,endstr 为第一个不能转换的字符的指针,base 为字符串 str 所采用的进制。当 base 的值为 0 时,默认采用 10 进制转换,若endptr 不为NULL,则会将遇到的不符合条件而终止的字符指针由 endptr 传回;若 endptr 为 NULL,则表示该参数无效,或不使用该参数****************************** setbuf *********************************void setbuf(FILE *stream, char *buf)使得文件打开后, 用户可建立自己设置的缓冲区, 而不使用fopen()打开文件设定的默认缓冲区大小buf = 0. 文件I/O不带缓冲************************************************************************/#include <stdio.h>#include "apue.h"#include <errno.h>#include <sys/time.h>// 不同系统的操作#if defined(MACOS)#include <sys/limits.h>#elif defined(SOLARIS)#include <limits.h>#elif defined(BSD)#include <sys/param.h>#endifunsigned long long count;struct timeval end;void checktime(char *str){struct timeval tv;// 获取当前的时间放入tv里面.gettimeofday(&tv, NULL);if(tv.tv_sec >= end.tv_sec && tv.tv_usec >= end.tv_usec){printf("%s %lld\n", str, count);exit(0);}}int main(int argc, char *argv[]){pid_t pid;char *s;int nzero, ret;int adj = 0;setbuf(stdout, NULL);#if defined(NZERO)nzero = NZERO;#elif defined(_SC_NZERO)nzero = sysconf(_SC_NZERO);#else#error NZERO undefined#endifprintf("NZERO = %d\n", nzero);if(argc == 2)// 转换为对应的整形adj = strtol(argv[1], NULL, 0);// 获得当前的时间gettimeofday(&end, NULL);end.tv_sec += 10;if((pid = fork()) < 0)err_sys("fork error");else if(pid == 0){s = "child";printf("current nice value in child is %d, adjusting by %d\n", nice(0) + nzero, adj);errno = 0;if((ret = nice(adj)) == -1 && errno != 0)err_sys("child set scheduling priority");printf("now child nice value in parent is %d\n", nice(0) + nzero);}else{s = "parent";printf("current nice value in parent is %d\n", nice(0) + nzero);}for(; ; ){if(++count == 0)err_quit("%s counter wrap", s);checktime(s);}}

博客主要介绍了C++在Linux/Unix环境下exec函数和system()函数的使用。exec函数用于替换进程的程序,不创建新进程;system()函数在实现中涉及fork(), waitpid(), exec()。文章提到了exec函数族的不同变体,如execlp()和execvp(),并讲解了如何处理脚本中的解释器。同时,还讨论了system()函数的返回值情况以及nice()值对进程优先级的影响。"
79804976,7506070,Visual Studio预编译头文件详解,"['C++', '开发工具', 'Visual Studio']
5753

被折叠的 条评论
为什么被折叠?



