Unix环境高级编程—进程控制(三)
一、解释器文件
解释器文件属于文本文件,起始行形式为:
#! pathname[optional-argument]
我们创建一个只有一行的文件如下:
#!/home/webber/test/echoall.c foo
然后通过进程fork一个子进程execl寻找到这个文件路径下,我们将看到的是/home/webber/test/echoall.c 作为第一个参数被传了进来,foo成为第二个参数,
然后才是execl函数内指定的其他argv的值。即exec族函数的处理是把#!后面的字符串做为命令,后面加上execl参数列表中指定。
在书中例子中,
#!/usr/bin/awk -f
-f 的选项是必须的,它告诉awk在什么地方找到awk程序。
二、函数system
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed.
During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.
system函数用于执行一个shell命令,它对fork、exec、waitpid的进行封装,变为一个对外的函数接口,进行了所需的各种出错处理和各种信号处理。
#include<stdlib.h>
int system(const char *cmdstring)
返回值:因为system在实现中调用了fork、exec、waitpid,所以有三种返回值。如下:
1) fork失败或waitpid返回除EINTR之外的出错,则system返回-1,并且设置errno来指示错误类型。
2) exec失败(表示不能执行shell),则返回值相当于shell执行exit(127),即返回定义的错误码(command not found)。
3) 三个调用的函数都执行成功,则system的返回值是shell的终止状态。(WIFEXITED,WIFSIGNALED,WIFSTOPPED,WIFCONTINUED)
The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command other- wise. This latter return status is in the
format specified in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case /bin/sh could not be executed,
the exit status will be that of a command that does exit(127).
If the value of command is NULL, system() returns non-zero if the shell is available, and zero if not. system() does not affect the wait
status of any other children.
注意:使用system函数调用在某些情况下需要谨慎。比如,一个进程以root权限运行,当它想生产一个子进程执行以普通用户权限就能执行的任务时,绝不能用system函数去开启子进程,因为system在fork一个子进程时把root的ID也复制给了子进程,然后立即exec去执行,这样当真正的子进程以普通用户权限去执行任务时,我们geteuid()会返回0,即子进程的有效用户ID具有root权限,这是很危险的安全漏洞。对于这种情况,我们应该在fork之后,exec之前改回普通用户权限,而不能调用封装好的system函数。
三、进程会计
accton(8)命令开启或关闭进程会计,每当进程结束时,内核就写一个会计记录,记录命令名、所使用的CPU时间总量、用户ID和组ID、启动时间等。在Linux中,
该记录写在/var/account/pacct文件中。会计记录所需的数据都由内核保存在进程表中,并在一个新进程fork被创建时初始化。进程终止时写一个会计记录。
这产生两个后果:
1).我们不能获取永远不终止的进程的会计记录。例如init、守护进程daemon
2).在会计文件中记录的顺序对应于进程终止的顺序,而非启动顺序。
注意:会计记录对应与进程而不是程序。在这里,我认为进程是大于程序的,可以表述为:
首先,父进程fork了一个子进程,然后子进程exec一个程序A(通过pathname等找到程序A),同时,该子进程还可以再exec一个程序B。因此说进程大于程序,
程序是用某一进程exec出来的。
再回到会计记录,在上述表述中,进程会计只会记录exec出来的程序B,但CPU时间是A、B之和。
一个人在口令文件中可以有多个登录项,它们的用户ID相同,但登陆shell不同。登录名由getlogin()函数获取。
四、进程调度
nice函数 属于系统调用,它的作用是通过调整nice值选择以更低的优先级运行,nice值越小,cpu占用率越高,进程越“友好”,优先级也就越高。
在Linux2.26.32内核版本中,nice值的范围为-20~19. ( Nicenesses range from -20 (most favorable scheduling) to 19 (least favorable).)
经过测试,在单核CPU的Linux系统中,如果两个进程并行运行,在相同nice值的情况下,我们top观察两个进程,会发现cpu占用大约各为50%,
但是如果其中一个进程调高了nice值,则系统会认为它不“友好”,从而给它分配更低的cpu占用率,它执行任务的效率会明显变低。
五、进程时间
times命令是内建命令。作用:
Print the accumulated user and system times for the shell and for processes run from the shell. The return status is 0.
time命令,作用:测量一个命令的运行的三种时间,分别为:实际使用时间(real time)、用户态使用时间(the process spent in user mode)、
内核态使用时间(the process spent in kernel mode)
times函数,返回墙上时钟时间,调用方式如下:
clock_t times(struct tms *buf);
buf指向的tms结构,该结构定义如下:
Struct tms {
clock_t tms_utime; /*user CPU time */
clock_t tms_stime; /*system CPU time */
clock_t tms_cutime; /*user CPU time ,terminated children*/
clock_t tms_cstime; /*system CPU time ,terminated children*/
}
下面是书中用times函数以及结合了整章知识点,写了一个具有time命令功能的程序。
其中,输入的argv[]需要有双引号。
#include "apue.h"
#include <sys/times.h>static void pr_times(clock_t, struct tms *, struct tms *);
static void do_cmd(char *);int
main(int argc, char *argv[])
{int i;setbuf(stdout, NULL);for (i = 1; i < argc; i++)do_cmd(argv[i]); /* once for each command-line arg */exit(0);
}static void
do_cmd(char *cmd) /* execute and time the "cmd" */
{struct tms tmsstart, tmsend;clock_t start, end;int status;printf("\ncommand: %s\n", cmd);if ((start = times(&tmsstart)) == -1) /* starting values */err_sys("times error");if ((status = system(cmd)) < 0) /* execute command */err_sys("system() error");if ((end = times(&tmsend)) == -1) /* ending values */err_sys("times error");pr_times(end-start, &tmsstart, &tmsend);
}static void
pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend)
{static long clktck = 0;if (clktck == 0) /* fetch clock ticks per second first time */if ((clktck = sysconf(_SC_CLK_TCK)) < 0)err_sys("sysconf error");printf(" real: %7.2f\n", real / (double) clktck);printf(" user: %7.2f\n",(tmsend->tms_utime - tmsstart->tms_utime) / (double) clktck);printf(" sys: %7.2f\n",(tmsend->tms_stime - tmsstart->tms_stime) / (double) clktck);printf(" child user: %7.2f\n",(tmsend->tms_cutime - tmsstart->tms_cutime) / (double) clktck);printf(" child sys: %7.2f\n",(tmsend->tms_cstime - tmsstart->tms_cstime) / (double) clktck);
}
Unix环境高级编程—进程控制(三)相关推荐
- unix环境高级编程----进程控制fock()函数
1.进程标识符 每一个进程,都有一个id来对其进行标示. 用getpid()就可以获取当前的进程的id 2.fork()函数 fork函数是创建一个进程,这个进程就是当前进程的子进程.子进程就是当前线 ...
- UNIX环境高级编程(第三版)关于apue.h的用法
UNIX环境高级编程(第三版)中的例子用到apue.h这个头文件,但是书里面写的地址已经不能访问. 经过一番查找之后,找到如下解决方案: 1.到www.apuebook.com上下载第2版的源码,也可 ...
- Unix环境高级编程—进程关系
终端登录 网络登录 进程组 getpgrp(void) setpgid(pid_t pid, pid_) 会话: 是一个或多个进程组的集合,通常由shell的管道将几个进程编成一组. setsid(v ...
- UNIX环境高级编程——进程关系
9.1 引言 本章详细说明进程组以及会话的概念,还将介绍登录shell(登录时所调用的)和所有从登录shell启动的进程之间的关系. 9.2 终端登录 9.3 网络登录 9.4 进程组 每个进程除了有 ...
- Unix环境高级编程中的apue.h配置
本文解释Unix环境高级编程的环境搭建中,apue.h如何使用安装及问题解决. 使用的是<Unix环境高级编程>第三版: 系统为CentOS 7.4,64位(Linux系统都可参考): 文 ...
- (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- UNIX环境高级编程-第三版
Unix环境高级编程-第三版 之前学习了<Linux系统编程>对于常见的概念和函数都有了基础的认知,这里准备通过这本书,深入学习系统API相关内容.笔记内容会有所倾向,不会严格反应书本内容 ...
- Linux - Unix环境高级编程(第三版) 代码编译
Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...
- UNIX环境高级编程(第三版 源码及编译好的静态库文件)
UNIX环境高级编程(第三版) 源码 及 库文件 链接: https://pan.baidu.com/s/1tPY17lWNDEbzkOwZaRUUNg 提取码: 1024 复制这段内容后打开百度网盘 ...
- 开发日记-20190827 关键词 读书笔记《Unix环境高级编程(第二版)》DAY 3
Referred Blogs 文件描述符标志,文件状态标志 Linux中文件描述符fd和文件指针flip的理解 Linux编程–文件描述符fd 文件共享 Unix支持在不同进程间共享文件. 内核使用了 ...
最新文章
- 利用gevent实现异步执行任务
- Redis 过滤请求绝技 — 布隆过滤器与布谷鸟过滤器
- android怎么判断程序进入了后台,Android检测应用程序是否进入后台
- ajax 设置Access-Control-Allow-Origin实现跨域访问
- Spring Boot(四)Spring Boot @ConfigurationProperties实例
- Delphi作为客户端调用.Net写的WCF服务端?
- [记录] --- safari浏览器对于yyyy-MM的坑
- 进程间通信之2----共享内存
- [think]需求从来就没变过,变的是我们对需求的理解
- WPF Splash Screen 和启动速度相关资料
- 循序渐进!java开发手册阿里巴巴泰山版
- java简易计算器程序框图_简易计算器程序设计思路及流程图
- 【杭电5053】the Sum of Cube
- 打造自己的ip代理池
- 「微服务」修改服务注册到nacos默认的命名空间和分组名称
- iOS判断第三方SDK是否含有广告位
- 《留住好员工》-读后感
- Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day39】—— 数据库6
- UGUI文本颜色渐变
- 微信公众号用户授权登录逻辑