进程调度和进程时间

进程调度: 

由内核决定:调度策略,调度优先级

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值