exec函数和system()函数

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >





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. 错误, 返回 -1; 成功, 不返回
  2. 前四个取路径名为参数。execlp()和execvp()取文件描述符为参数, 但是如果filename包含 “/”就取路径名, 否则按照PATH环境变量搜寻可执行文件(一般是shell文件)。
  3. execl(), execle(), execlp()函数最后参数以 “NULL”结尾。
  
  
  1. /*************************************************************************
  2. > File Name: environ_打印环境表参数.cpp
  3. > Author: Function_Dou
  4. > Mail:
  5. > Created Time: 2018年02月01日 星期四 21时58分25秒
  6. ************************************************************************/
  7. #include <stdio.h>
  8. #include "apue.h"
  9. int main(int argc, char *argv[])
  10. {
  11. int i;
  12. char **ptr;
  13. extern char **environ;
  14. for(i = 0; i < argc; i++)
  15. printf("argv[%d] : %s\n", i, environ[i]);
  16. // 输出所有的环境变量
  17. for(ptr = environ; *ptr != 0; ptr++)
  18. printf("%s\n", *ptr);
  19. exit(0);
  20. }

解释器

解释器就是#! 后面可执行的程序。
对于解释器,exec族函数是这样做的(以execl为例),如果path是指向了一个脚本,脚本的第一行以#!开头,则:以#!后面的字符串为命令,后面加上execl参数列表中指定的参数列表,这样形成了新的程序执行。

如何理解解释器呢, 我看了些资料按照自己的思路整理了下。
先创建了一个cpp文件

  
  
  1. /*************************************************************************
  2. > File Name: jieshiqi.cpp
  3. > Author: Function_Dou
  4. > Mail:
  5. > Created Time: 2018年02月01日 星期四 22时18分59秒
  6. ************************************************************************/
  7. #include <stdio.h>
  8. int main(int argc, char *argv[])
  9. {
  10. int i;
  11. for(i = 0; i < argc; i++)
  12. printf("argv[%d] : %s\n", i, argv[i]);
  13. return 0;
  14. }

又写了一个脚本

  
  
  1. #!/home/RPZ/Code/Cc++/Process/a.out Function
  2. # 这是我jieshiqi.cpp生成的a.out的位置

当然权限要设置够

  
  
  1. -rwxr-xr-x. 1 root root 44 2 1 22:21 JSQ

最后运行JSQ, 结果就出来了

  
  
  1. [root@192 Process]# ./JSQ
  2. argv[0] : /home/RPZ/Code/Cc++/Process/a.out
  3. argv[1] : Function
  4. argv[2] : ./JSQ
  1. 开始时讲到的,exec族函数的处理是把#!后面的字符串为命令,后面加上execl参数列表中指定的参数列表,这样形成了新的程序执行
  2. 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() 函数

  
  
  1. #include <stdlib.h>
  2. int system("cosnt char *cmdstring);
  • 关于返回值

system()在实现中调用了fork(), waitpid(), exec()函数
1. fork失败或者waitpid返回除EINTR之外的出错, 则system返回 -1, 并设置errno已指示错误类型
2. exec失败, 返回值如同shell执行exit一样
3. 3个函数都成功了, system返回值是shell的终止状态

  
  
  1. /*************************************************************************
  2. > File Name: system_函数的实现.cpp
  3. > Author: Function_Dou
  4. > Mail:
  5. > Created Time: 2018年02月01日 星期四 22时43分18秒
  6. ************************************************************************/
  7. #include <stdio.h>
  8. #include <sys/wait.h>
  9. #include <errno.h>
  10. #include <unistd.h>
  11. #include "apue.h"
  12. int system(const char *cmdstring)
  13. {
  14. pid_t pid;
  15. int status;
  16. if(cmdstring == NULL)
  17. return 1;
  18. if((pid = fork()) < 0)
  19. status = -1;
  20. else if(pid == 0)
  21. {
  22. // shell 的-c选项是告诉shell程序读取下一个命令行参数(这里是cmdstring)作为命令输入(而不是从标准输入或者指定文件读命令);
  23. execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
  24. _exit(0);
  25. }
  26. else
  27. while(waitpid(pid, &status, 0) < 0)
  28. if(errno != EINTR)
  29. {
  30. status = -1;
  31. break;
  32. }
  33. return status;
  34. }
  35. void
  36. pr_exit(int status)
  37. {
  38. if (WIFEXITED(status))
  39. printf("normal termination, exit status = %d\n",
  40. WEXITSTATUS(status));
  41. else if (WIFSIGNALED(status))
  42. printf("abnormal termination, signal number = %d%s\n",
  43. WTERMSIG(status),
  44. #ifdef WCOREDUMP
  45. WCOREDUMP(status) ? " (core file generated)" : ""
  46. #else
  47. ""
  48. #endif
  49. );
  50. else if (WIFSTOPPED(status))
  51. printf("child stopped, signal number = %d\n", WSTOPSIG(status));
  52. }
  53. int main(void)
  54. {
  55. int status;
  56. if((status = system("date")) < 0)
  57. err_sys("system() error");
  58. pr_exit(status);
  59. if((status = system("no file")) < 0)
  60. err_sys("system() error");
  61. pr_exit(status);
  62. if((status = system("who; exit 44")) < 0)
  63. err_sys("system() error");
  64. pr_exit(status);
  65. exit(0);
  66. }
  67. /* 样列
  68. *
  69. [root@192 Process]# ./a.out
  70. 2018年 02月 01日 星期四 22:57:00 CST
  71. normal termination, exit status = 0
  72. sh: no: 未找到命令
  73. normal termination, exit status = 127
  74. root :2 2018-02-01 14:30 (:2)
  75. root pts/0 2018-02-01 20:58 (:2)
  76. root pts/1 2018-02-01 21:40 (:2)
  77. root pts/2 2018-02-01 21:56 (:2)
  78. normal termination, exit status = 44
  79. */

如果在调用system就已经有了子进程, 那么就将出问题.


nice()值的效果

这里具体只写了一个程序, 将书上的那个程序进行了解释

  
  
  1. /*************************************************************************
  2. > File Name: nice_调度.cpp
  3. > Author: Function_Dou
  4. > Mail:
  5. > Created Time: 2018年02月02日 星期五 11时53分18秒
  6. *************************** timeval ***********************************
  7. struct timeval
  8. {
  9. long tv_sec; //秒
  10. long tv_usec; //微秒
  11. };
  12. struct timezone
  13. {
  14. int tz_minuteswest; //和Greenwich 时间差了多少分钟
  15. int tz_dsttime; //日光节约时间的状态
  16. };
  17. *************************** gettimeofday *******************************
  18. int gettimeofday (struct timeval * tv, struct timezone * tz);
  19. gettimeofday 会把目前的时间放入tv, 结构中, 当地时区的信息则放入tz结构中.
  20. 返回值:成功则返回0,失败返回-1,错误代码存于errno。
  21. *************************** nice **************************************
  22. int nice(int inc);
  23. nice()用来改变进程的进程执行优先顺序. 参数inc 数值越大则优先顺序排在越后面, 即表示进程执行会越慢. 只有超级用户才能使用负的inc 值, 代表优先顺序排在前面, 进程执行会较快.
  24. 如果执行成功则返回0, 否则返回-1, 失败原因存于errno 中.
  25. **************************** strtol ***********************************
  26. long int strtol (const char* str, char** endptr, int base);
  27. strtol() 函数用来将字符串转换为长整型数(long)
  28. str 为要转换的字符串,endstr 为第一个不能转换的字符的指针,base 为字符串 str 所采用的进制。
  29. 当 base 的值为 0 时,默认采用 10 进制转换,
  30. 若endptr 不为NULL,则会将遇到的不符合条件而终止的字符指针由 endptr 传回;若 endptr 为 NULL,则表示该参数无效,或不使用该参数
  31. ****************************** setbuf *********************************
  32. void setbuf(FILE *stream, char *buf)
  33. 使得文件打开后, 用户可建立自己设置的缓冲区, 而不使用fopen()打开文件设定的默认缓冲区大小
  34. buf = 0. 文件I/O不带缓冲
  35. ************************************************************************/
  36. #include <stdio.h>
  37. #include "apue.h"
  38. #include <errno.h>
  39. #include <sys/time.h>
  40. // 不同系统的操作
  41. #if defined(MACOS)
  42. #include <sys/limits.h>
  43. #elif defined(SOLARIS)
  44. #include <limits.h>
  45. #elif defined(BSD)
  46. #include <sys/param.h>
  47. #endif
  48. unsigned long long count;
  49. struct timeval end;
  50. void checktime(char *str)
  51. {
  52. struct timeval tv;
  53. // 获取当前的时间放入tv里面.
  54. gettimeofday(&tv, NULL);
  55. if(tv.tv_sec >= end.tv_sec && tv.tv_usec >= end.tv_usec)
  56. {
  57. printf("%s %lld\n", str, count);
  58. exit(0);
  59. }
  60. }
  61. int main(int argc, char *argv[])
  62. {
  63. pid_t pid;
  64. char *s;
  65. int nzero, ret;
  66. int adj = 0;
  67. setbuf(stdout, NULL);
  68. #if defined(NZERO)
  69. nzero = NZERO;
  70. #elif defined(_SC_NZERO)
  71. nzero = sysconf(_SC_NZERO);
  72. #else
  73. #error NZERO undefined
  74. #endif
  75. printf("NZERO = %d\n", nzero);
  76. if(argc == 2)
  77. // 转换为对应的整形
  78. adj = strtol(argv[1], NULL, 0);
  79. // 获得当前的时间
  80. gettimeofday(&end, NULL);
  81. end.tv_sec += 10;
  82. if((pid = fork()) < 0)
  83. err_sys("fork error");
  84. else if(pid == 0)
  85. {
  86. s = "child";
  87. printf("current nice value in child is %d, adjusting by %d\n", nice(0) + nzero, adj);
  88. errno = 0;
  89. if((ret = nice(adj)) == -1 && errno != 0)
  90. err_sys("child set scheduling priority");
  91. printf("now child nice value in parent is %d\n", nice(0) + nzero);
  92. }
  93. else
  94. {
  95. s = "parent";
  96. printf("current nice value in parent is %d\n", nice(0) + nzero);
  97. }
  98. for(; ; )
  99. {
  100. if(++count == 0)
  101. err_quit("%s counter wrap", s);
  102. checktime(s);
  103. }
  104. }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值