UNIX高级环境编程(11)进程控制(Process Control)- 进程快照,用户标识符,进程调度

1 进程快照(Process Accounting)

当一个进程终止时,内核会为该进程保存一些数据,包括命令的小部分二进制数据、CPU time、启动时间、用户Id和组Id。这样的过程称为process accounting,本篇译为进程快照。

函数acct可以打开或关闭进程快照功能。

负责记录快照的数据结构如下所示:

成员说明:

  • ac_flag成员记录进程执行过程中的特定事件(稍后的表中会详细说明);
  • 进程创建时,初始化进程快照的数据在进程表(process table)中,但是只有在进程终止才会写进程快照。这样的机制导致了两个结果:
    • 如果进程不终止,我们无法获取进程快照
    • 进程快照文件的顺序依赖于进程终止的顺序,而不是进程被创建的顺序
  • 进程快照对应一个进程,而不是程序。进程快照在进程被创建(fork)的时候被初始化,而不是程序被执行时,所以如果我们有一个程序链:A execs B, B execs C然后C退出,则只有一个进程快照被保存。命令的名字是程序的C决定,而CPU时间这类信息则是ABC的总和。

ac_flag不同的取值代表的事件含义如下表所示:

2  用户标识符(User Identification)

进程可以知道它的真实用户和组(real user ID and group ID),有效用户和组(effective user ID and group ID)。

然后有时候我们想知道运行程序的登录用户名。函数getpwuid可以实现。

函数声明:

#include <unistd.h>

char* getlogin(void);

// Returns: pointer to string giving login name if OK, NULL on error

函数细节:

  • 如果进程并没有和一个终端关联,即没有一个登录用户,则该函数失败,不和终端关联的进程被称为daemon
  • 有了登录用户名,我们可以在password文件中找到该用户,然后确定登录终端,例如使用getpwnam函数。

3 进程调度(Process Scheduling)

nice值决定了进程的运行优先级。

取值范围:0 ~ (2 * NZERO -1)

nice值越低,优先级越高。

意思就是:进程越好,进程的优先级越高。

nice值的默认值为NZERO。

函数nice可以获取并修改nice值。

进程调用nice函数只能修改它自己的nice值。

函数声明:

#include <unistd.h>

int nice(int incr);

// Returns: new nice value - NZERO if OK, -1 on error

函数说明:

  • 函数的作用是将当前进程的nice值加上参数incr作为新的nice值。
  • 如果incr的值太大,则系统会自动将结果调整为最大的有效值;
  • 如果incr的值太小,则系统会自动将结果调整为最小的有效值,即-1。
  • 因为-1是一个合法的返回值,所以判断nice函数是否成功调用需要同时判断函数返回值和errno。在调用nice函数之前将errno清0。如果返回值为-1,errno为0.则调用成功,如果返回值和errno都为-1,则调用失败。

函数getpriority可以用来获取一个进程的nice值。

函数声明:

#include <sys/resource.h>

int getpriority(int which , id_t who);

// Returns: nice value between -NZERO和NZERO-1之间 if OK, -1 on error

参数说明:

which:有三个可取值:PRIO_PROCESS表明是一个进程,PRIO_PGRP表明是一个进程组,PRIO_USER表明目标是一个用户。

which参数的作用是控制who的含义,以及who参数如何选择进程。

如果who取值为0,则函数返回当前调用进程、进程组或用户的nice值。

如果which取值为PRIO_USER,who取值0,则返回当前进程的真实用户ID(real user Id)。

如果which取值为PRIO_GROUP,则返回所有进程中priority最高,即nice值最低的进程的nice值。

设置nice值使用函数setpriority。

函数声明:

#include <sys/resource.h>

int setpriority(int which, id_t who, int value);

参数的作用和getpriority相同。

value的值被加到nice默认值NZERO上,设置该值为新的nice值。

4 进程时间(Process Times)

进程时间包括:墙上时间(wall clock tie),用户CPU时间(user CPU time),内核CPU时间(system CPU time).

函数times可以获取这三种时间。

函数声明:

#include <sys/times.h>

clock_t times(struct tms *buf);

函数细节:

函数会向结构体struct tms类型的变量中填充上面的三个时间,struct tms结构体的声明如下:

墙上时间为该函数的返回值。墙上时间为从过去某个时间点到现在的时间,所以不能直接作为时间来使用。

大多情况下,我们可以通过times的返回值来计算相对时间,例如,在进程开始和结束时分别调用times函数,然后相减来计算进程的运行时间。

两个子进程时间变量用来保存父进程调用wait函数等待子进程退出的时间。

Example

程序功能:执行命令行传入的命令,计算每个命令执行的时间,并打印结构体tms中的成员值。

code

#include "apue.h"

#include <sys/times.h>

static void pr_times(clock_t, struct tms *, struct tms *);

staticvoid 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);

}

staticvoid

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);

pr_exit(status);

}

staticvoid

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);

}

运行结果:

小结

进程控制章节介绍了以下内容:

  • fork
  • exec
  • _exit
  • wait和waitpid
  • system
  • 解释器文件(interpreter files)和他们的工作原理
  • 进程时间

下一章我们将会学习到进程关系(process relationship),关键字:sessions,job control。

参考资料:

《Advanced Programming in the UNIX Envinronment 3rd》

时间: 2024-10-10 11:57:58

UNIX高级环境编程(11)进程控制(Process Control)- 进程快照,用户标识符,进程调度的相关文章

《unix高级环境编程》终端 I/O——终端 IO 基本概述

终端基本概念 终端 IO 是一种字符型设备,终端特殊设备文件一般有以下几种: 串行端口终端:是使用计算机串行端口连接的设备,计算机把每个串行端口都看作是一个字符设备.串行端口所对应的设备名称 /dev/ttySn(n表示从0开始的整数): 伪终端:是成对的逻辑终端设备,例如 /dev/ptyp3 和/ dev/ttyp3(在设备文件系统中分别是 /dev/pty/m3 和/ dev/pty/s3 ),它们与实际物理设备并不直接相关: 控制终端:是当前进程的控制终端的设备特殊文件 /dev/tty

UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID ? 1 进程标识符(Process Identifiers) 每个进程都有一个唯一的标识符,进程ID(process ID). 进程的ID是可重用的,如果一个进程被终止,那么它的进程ID会被系统回收,但是会延迟使用,防止该进程ID标识的新进程被误认为是以前的进程. 三个特殊ID的进程: Process ID 0:调度者进程,内核进程. Process

UNIX高级环境编程(12)进程关联(Process Relationships)- 终端登录过程 ,进程组,Session

在前面的章节我们了解到,进程之间是有关联的: 每个进程都有一个父进程: 子进程退出时,父进程可以感知并且获取子进程的退出状态. 本章我们将了解: 进程组的更多细节: sessions的内容: login shell和我们从login shell启动的进程之间的关系. ? 一 终端登录(Terminal Logins) BSD Terminal Logins ?BSD终端的登录程序在过去35年都没有改变. 系统管理员(the system adminstrator)创建一个文件 /etc/ttys

UNIX高级环境编程(8)进程环境(Process Environment)- 进程的启动和退出、内存布局、环境变量列表

在学习进程控制相关知识之前,我们需要了解一个单进程的运行环境. 本章我们将了解一下的内容: 程序运行时,main函数是如何被调用的: 命令行参数是如何被传入到程序中的: 一个典型的内存布局是怎样的: 如何分配内存: 程序如何使用环境变量: 程序终止的各种方式: 跳转(longjmp和setjmp)函数的工作方式,以及如何和栈交互: 进程的资源限制 ? 1 main函数 main函数声明: int main (int argc, char *argv[]); 参数说明: argc:命令行参数个数

UNIX高级环境编程(15)进程和内存分配 &lt; 故宫角楼 &gt;

故宫角楼是很多摄影爱好者常去的地方,夕阳余辉下的故宫角楼平静而安详. ? 首先,了解一下进程的基本概念,进程在内存中布局和内容. 此外,还需要知道运行时是如何为动态数据结构(如链表和二叉树)分配额外内存的. 一 进程 1 进程和程序 进程:是一个可执行程序的实例. 程序:包含一系列信息的文件,这些信息描述了如何在运行时创建一个进程.包含如下信息: 二进制格式标识:如最常见的ELF格式. 机器语言指令:对程序算法进行编码. 程序入口地址:标识程序开始执行时的起始指令位置. 数据:程序文件包含的变量

UNIX高级环境编程--1

前期准备: 下载apue3源文件(从apuebook.com上),然后编译(make)之后,得到libapue.a动态链接文件(.o 就相当于windows里的obj文件 .a 是好多个.o合在一起,用于静态连接 .so 是shared object,用于动态连接的,和dll差不多). 把apue.h放到 usr/include中,libapue.a放到usr/local/lib中. 如果想要在IDE中编译书中的source_code.c那么要记得设置项目或者文件的 "build option&

UNIX高级环境编程(5)Files And Directories - 文件相关时间,目录文件相关操作

?1 File Times 每个文件会维护三个时间字段,每个字段代表的时间都不同.如下表所示: 字段说明: st_mtim(the modification time)记录了文件内容最后一次被修改的时间. st_ctim(the changed-status time)记录了文件的i-node最后一次被修改的时间,如修改文件权限位,修改文件所有者ID,修改关联到该文件的link数目. i-node中的信息和文件的实际内容是分离的,所以当更新i-node时,需要更新的时st_ctim(the ch

UNIX高级环境编程(13)信号 - 概念、signal函数、可重入函数

信号就是软中断. 信号提供了异步处理事件的一种方式.例如,用户在终端按下结束进程键,使一个进程提前终止. ? 1 信号的概念 每一个信号都有一个名字,它们的名字都以SIG打头.例如,每当进程调用了abort函数时,都会产生一个SIGABRT信号. 每一个信号对应一个正整数,定义在头文件<signal.h>中. 没有信号对应整数0,kill函数使用信号编号0表示一种特殊情况,所以信号编号0又叫做空信号(null signal). 下面的各种情况会产生一个信号: 当用户在终端按下特定的键时,会产生

UNIX高级环境编程(2)FIle I/O - 原子操作、共享文件描述符和I/O控制函数

引言: 本篇通过对open函数的讨论,引入原子操作,多进程通信(共享文件描述符)和内核相关的数据结构. 还会讨论集中常见的文件IO控制函数,包括: dup和dup2 sync,fsync和fdatasync fcntl ioctl /dev/fd ? 一.文件共享 这里所说的文件共享主要指的是进程间共享打开的文件. 这一节主要讨论文件在进程间共享的理论基础和数据结构,不涉及具体的技术实现,不同的系统可能会有不同的实现. 每一个打开的文件,涉及内核中的三种数据结构,这三种数据结构也是文件在进程间共