一、解释器文件

解释器文件属于文本文件,起始行形式为:

#! 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环境高级编程—进程控制(三)的更多相关文章

  1. UNIX环境高级编程——进程控制

    一.进程标识符 ID为0的进程是调度进程,常常被称为交换进程.该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程.进程ID 1通常是init进程,在自举过程结束时由内核调用.ini ...

  2. Unix环境高级编程—进程控制(二)

    一.函数wait和waitpid 今天我们继续通过昨天那个死爹死儿子的故事来讲(便于记忆),现在看看wait和waitpid函数. #include<sys/wait.h> pid_t w ...

  3. unix环境高级编程----进程控制wait()

    一.wait()函数 当一个进程中调用wait()函数的时候 (1)假设其全部的子程序都还在执行,则堵塞 (2)假设一个子进程已终止.则等待父进程获取其终止状态. (3)假设没有子进程,则返回错误. ...

  4. UNIX环境高级编程(第三版)关于apue.h的用法

    UNIX环境高级编程(第三版)中的例子用到apue.h这个头文件,但是书里面写的地址已经不能访问. 经过一番查找之后,找到如下解决方案: 1.到www.apuebook.com上下载第2版的源码,也可 ...

  5. UNIX环境高级编程——进程管理和通信(总结)

    进程管理与通信 进程的管理 进程和程序的区别: 进程: 程序的一次执行过程   动态过程,进程的状态属性会发生变化 程序:存放在磁盘上的指令.数据的有序集合  是个文件,可直观看到 程序program ...

  6. UNIX环境高级编程——进程基本概述

    一.什么是进程 从用户的角度来看进程是程序的一次执行过程.从操作系统的核心来看,进程是操作系统分配的内存.CPU时间片等资源的基本单位.进程是资源分配的最小单位.每一个进程都有自己独立的地址空间与执行 ...

  7. UNIX环境高级编程——进程关系

    一.终端的概念 在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(Controlling Terminal),控制终端是保存在PCB中的信息,而我们 ...

  8. Unix环境高级编程—进程关系

    终端登录 网络登录 进程组 getpgrp(void) setpgid(pid_t pid, pid_) 会话: 是一个或多个进程组的集合,通常由shell的管道将几个进程编成一组. setsid(v ...

  9. UNIX环境高级编程——进程环境

    一.main函数 C程序总是从main函数开始.当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址--这是由连接编译器设置的,而连接编译器则由 ...

随机推荐

  1. hdu3452 无向树去掉最小的边集使任何叶子与根不连通 / 最小割

    思路一下就上来了,叶子向汇点连边,inf保证不会成为割,跑根到汇点最小割即可.注意无向树双向建边.基础题,分分钟1A: #include<iostream> #include<que ...

  2. LeetCode OJ-- Valid Sudoku

    https://oj.leetcode.com/problems/valid-sudoku/ 给出数独的一部分来,验证给出的这一部分是否为 valid 行上无重复的,且是从 ‘1’ 到‘9’ 列上无重 ...

  3. android日期时间选择器

    android原生的日期时间控件,因为是原生的总有其满足不了我们需求的时候,Android 手机版本那么多,用户弹出来的控件五花八门.因为项目需要,在网上找了一 些demo看了看,感觉有些写的很好,很 ...

  4. 伪造服务钓鱼工具Ghost Phisher

    伪造服务钓鱼工具Ghost Phisher   Ghost Phisher是一款支持有线网络和无线网络的安全审计工具.它通过伪造服务的方式,来收集网络中的有用信息.它不仅可以伪造AP,还可以伪造DNS ...

  5. Java NIO.2 Files类的常用方法

    Files类是一个工具类,提供了大量的静态方法来操作文件.文件夹. Files类常用方法: long size(Path  path)    //返回文件大小 boolean  isDirectory ...

  6. Java中获取当前时间并格式化

    主要有两种方式,其中使用Date比较好控制,代码如下: //使用Calendar Calendar now = Calendar.getInstance(); System.out.println(& ...

  7. 各语言最原始数据库访问组件封装DBHelper

    源码:https://github.com/easonjim/DBHelper bug提交:https://github.com/easonjim/DBHelper/issues 每个语言放在不同的分 ...

  8. eos wasm虚拟机相关接口定义实现

    wasm虚拟机相关接口定义实现 执行流程 controller::push_transaction()  // 事务 -> transaction_context::exec()  // 事务 ...

  9. Web攻防之XSS,CSRF,SQL注入(转)

    摘要:对Web服务器的攻击也可以说是形形色色.种类繁多,常见的有挂马.SQL注入.缓冲区溢出.嗅探.利用IIS等针对Webserver漏洞进行攻击.本文结合WEB TOP10漏洞中常见的SQL注入,跨 ...

  10. hdu3591The trouble of Xiaoqian 多重背包+全然背包

    //给出Xiaoqian的钱币的价值和其身上有的每种钱的个数 //商家的每种钱的个数是无穷,xiaoqian一次最多付20000 //问如何付钱交易中钱币的个数最少 //Xiaoqian是多重背包 / ...