进程调度:
由内核决定:调度策略,调度优先级
nice值决定优先级,nice越低优先级越高
nice的范围在 [ 0 , 2* NZERO - 1 ]
NZERO是系统默认的nice值
只有特权进程允许提高调度权限
关于NZERO:定义NZERO的头文件因系统而异,除了头文件,Linux3.2 可以通过非标准的sysconf参数 _SC_NZERO 来访问NZERO的值
获得或修改进程的nice值(进程使用nice(2)制会修改自己的nice值)
nice(2)
setpriority(2)
getpriority(2)
eg:更改nice值的效果
#include <apue.h>
#include <sys/time.h>
#include <errno.h>
#if defined(MACOS)
#include <sys/syslimits.h>
#elif defined(SOLARIS)
#include <limits.h>
#elif defined(BSD)
#include <sys/param.h>
#endif
void checktime(char *ptr);
#define handle_error(msg) \
do { perror(msg); return EXIT_FAILURE; } while (0)
unsigned long long count;
struct timeval end;
int main(int argc, char *argv[])
{
int adj = 0;
int nzero, ret;
char *s;
pid_t pid;
setbuf(stdout, NULL);
#ifdef NZERO
nzero = NZERO;
#elif defined(_SC_NZERO)
nzero = sysconf(_SC_NZERO);
#else
#error NZERO undefined
#endif
printf("NZERO = %d\n", nzero);
if (argc == 2)
adj = strtol(argv[1], NULL, 10);
if (gettimeofday(&end, NULL) < 0)
handle_error("gettimeofday");
end.tv_sec += 10; // run 10s
if ((pid = fork()) < 0)
handle_error("fork");
else if (pid == 0) {
s = "child";
printf("current nice value in child = %d, adjusting by %d\n", nice(0)+nzero, adj);
errno = 0;
if ((ret = nice(adj)) < 0 && errno != 0)
handle_error("nice");
printf("now child nice value is %d\n", nice(0)+nzero);
} else {
s = "parent";
printf("current nice value in parent = %d\n", nice(0)+nzero);
}
while(1) {
//printf("count = %lld\n", count);
if (++count == 0)
printf("%s counter wrap\n", s);
checktime(s);
}
exit(0);
}
void checktime(char *ptr)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0)
perror("gettimeofday in checktime");
if (tv.tv_sec >= end.tv_sec && tv.tv_usec >= end.tv_usec) {
fprintf(stdout, "%s count = %lld\n", ptr, count);
exit(0);
}
}
./a.out
./a.out 20
可以发现调度程序如何在不同nice值的进程之间进行CPU共享
进程时间
Unix维护三个进程时间:
1. 时钟时间(墙上时钟时间)
2. 用户CPU时间
3. 系统CPU时间
(2 + 3 和称为CPU时间)
使用times(2)获取进程自己以及终止子进程的三个进程时间
times的参数buf指向 tms 结构, 定义如下:
struct tms{
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
分别代表:用户CPU时间,系统CPU时间,子进程的用户CPU时间,子进程的系统CPU时间
tms结构没有包含进程的时钟时间(墙上时钟时间),times(2)将时钟时间作为返回值返回,它是相对过去度量的。
因此我们计算的时候可以调用两次求差值,求得时钟时间。(长时间运行的程序 时钟时间可能溢出)
所有由此函数返回的 clock_t 值,都用 _SC_CLK_TCK (由 sysconf 函数返回的每秒时钟滴答数)转换成秒数。
#include <apue.h>
#include <sys/times.h>
#include "pr_exit.h"
static void do_cmd(char *cmd);
static void pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend);
int main(int argc, char *argv[])
{
int i;
setbuf(stdout, NULL);
for (i = 1; i < argc; ++i)
do_cmd(argv[i]);
exit(0);
}
static void do_cmd(char *cmd)
{
struct tms tmsstart, tmsend;
clock_t start, end;
int status;
if ((start = times(&tmsstart)) < 0)
perror("times start");
if ((status = system(cmd)) < 0)
perror("system");
if ((end = times(&tmsend)))
perror("times end");
pr_times(end-start, &tmsstart, &tmsend);
pr_exit(status);
}
static void pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend)
{
static long clktck = 0;
if (clktck == 0)
if ((clktck = sysconf(_SC_CLK_TCK)) < 0)
perror("sysconf");
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_cstime - tmsstart->tms_cstime) / (double) clktck);
printf("child sys : %7.2f\n", (tmsend->tms_cutime - tmsstart->tms_cutime) / (double) clktck);
}
测试:
./a.out "sleep 10" "date" "man bash > /dev/null"
可以发现,因为用的是system(3)执行程程序(system实际用的是fork和exec),在命令运行时间足够长的时候子程序CPU时间出现计数。
利用 _SC_CLK_TCK参数到 sysconf 取得时钟滴答数,将时间转换为秒为单位
对于wait和waitpid返回的状态值
可以用 <sys/wait.h> 中定义的宏来进行测试,提取结果
pr_exit.h 文件如下:
#include <apue.h>
#include <sys/wait.h>
/*
* judge the status return from wait(2) or waitpid(2)
*/
void pr_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d %s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}