工学1号馆

home

« | 返回首页 | »

Unix进程调度优先级函数

By Wu Yudong on November 21, 2016

APUE8.16中讲到进程调度,UNIX系统历史上对进程提供的只是基于调度优先级的粗粒度的控制,调度策略和调度优先级是由内核确定的,但是内核可以通过调整nice值选择以更低优先级运行(通过调整nice值降低它对cpu的占有,因此该进程是"友好的"),只有特权进程允许提高调度权限。

本文地址:http://wuyudong.com/2016/11/21/3070.html,转载请注明出处。

POSIX可移植操作系统接口实时扩展增加了在多个调度类别中选择的接口以进一步细调行为,APUE中只讨论了用于调整nice值的接口,其中nice值越小,优先级越高。系统的默认nice值为NZERO,将新的nice值加到NZERO

注意:定义 NZERO 的头文件因系统而异,除了头文件外,linux 可以通过非标准的 sysconf 参数(_SC_NZERO)来访问 NZERO 的值,进程可以通过nice函数来获取或修改它自己的nice值

#include<unistd.h>
int nice(int incr); //返回值:若成功,返回新的nice值;若出错,返回-1

incr被增加到调用进程的nice值上。如果nice过大或过小,都会被系统降到最大合法值或提高到最小合法值。

注意:因为 -1 是合法的成功返回值,所以会被误认为是错误返回,这里解决办法是要查看errno的值,errno在标准C中是一个整形变量,为防止和正常的返回值混淆,系统调用并不直接返回错误码,而是将错误码放入一个名为 errno 的全局变量中。如果一个系统调用失败,你可以读出 errno 的值来确定问题所在。如果nice返回-1,需要检查它的值。如果nice成功调用,并且返回值是-1,errno的值应该为0。如果不是0,说明nice值调用失败。为了有所区别,先将errno清为0并在事后检查它的值.

getpriority函数可以像nice函数获取进程nice值,而且他还可以获取一组相关进程的nice值.

#include <sys/resource.h>
int getpriority(int which, id_t who); //返回值:若成功,返回nice值;若失败,返回-1

which参数可以取以下三个值之一:PRIO_PROCESS表示进程,PRIO_PGRP表示进程组,PRIO_USER表示用户ID。which参数控制who参数如何解释,如果who为0,表示调用进程,进程组或者用户(取决与which参数的值).

setpriority函数可用于进程、进程组和属于特定用户ID的所有进程设置优先级:

#include <sys/resource.h>
int setpriority(int which,id_t who, int value); //返回值:若成功,返回0;若失败,返回-1

参数和getpriority一样,其中value增加到NZERO 上成为新的nice值。

注意:子进程从父进程中继承nice

进程cpu资源分配就是指进程的优先权(priority)。优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

接下来实践一下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <errno.h>
#include <sys/time.h>

#if defined(MACOS)
#include <sys/syslimits.h>
#elif defined(SOLARIS)
#include <limits.h>
#elif defined(BSD)
#include <sys/param.h>
#endif

unsigned long long count;
struct timeval end;

void
checktime(char *str)
{
    struct timeval    tv;

    gettimeofday(&tv, NULL);
    if (tv.tv_sec >= end.tv_sec && tv.tv_usec >= end.tv_usec) {
        printf("%s count = %lld\n", str, count);
        exit(0);
    }
}

int
main(int argc, char *argv[])
{
    pid_t    pid;
    char     *s;
    int      nzero, ret;
    int      adj = 0;

    setbuf(stdout, NULL);
#if defined(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);
    gettimeofday(&end, NULL);
    end.tv_sec += 10;    /* 运行10s */

    if ((pid = fork()) < 0) {
        printf("fork failed\n");
    } else if (pid == 0) {    /* 子进程 */
        s = "child";
        printf("current nice value in child is %d, adjusting by %d\n",
          nice(0)+nzero, adj);
        errno = 0; // 使用前清零
        if ((ret = nice(adj)) == -1 && errno != 0) //nice函数执行失败
            printf("child set scheduling priority\n");
        printf("now child nice value is %d\n", ret+nzero);
    } else {        /* 父进程 */
        s = "parent";
        printf("current nice value in parent is %d\n", nice(0)+nzero);
    }
    for(;;) {
        if (++count == 0)
            printf("%s counter wrap\n", s);
        checktime(s);
    }
}

编译运行:

wu@ubuntu:~/linuxc$ ./nice
NZERO = 20
current nice value in parent is 20
current nice value in child is 20, adjusting by 0
now child nice value is 20
parent count = 31796694
child count = 31806132
wu@ubuntu:~/linuxc$ ./nice 20
NZERO = 20
current nice value in parent is 20
current nice value in child is 20, adjusting by 20
now child nice value is 39
parent count = 61513236
child count = 890923

其中:

struct timeval结构体在time.h中的定义为:

struct timeval
{
    __time_t tv_sec;        /* Seconds. */
    __suseconds_t tv_usec;  /* Microseconds. */
};

它获得的时间精确到微秒(1e-6 s)量级。其中,tv_sec为Epoch(1970-01-01 00:00:00)到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。

gettimeofday()函数:

#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);

其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果:

struct timezone{
    int tz_minuteswest;   /*格林威治时间往西方的时差*/
    int tz_dsttime;   /*DST 时间的修正方式*/
}

在一段代码前后分别使用gettimeofday可以计算代码执行时间:

struct timeval tv_begin, tv_end;
gettimeofday(&tv_begin, NULL);
function();
gettimeofday(&tv_end, NULL)

写个程序测试一下这几个函数:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>

int main(void)
{
    int i, j;
    double timeUsec;
    unsigned long timeSec, sum = 0LL;
    struct timeval begin, end;
    gettimeofday(&begin, NULL);

    for(i = 0; i < 100000; i++)
        for(j = 0; j < 100000; j++)
            sum += i + j;

    gettimeofday(&end, NULL);
    timeSec = (end.tv_sec - begin.tv_sec) * 100000 + end.tv_usec - begin.tv_usec;
    printf("the loop take %ld microsecond\n",  timeSec);
    timeUsec = (double)timeSec / 1000000;
    printf("the loop take %lf second\n",  timeUsec);
    return 0;
}

编译运行:

wu@ubuntu:~/linuxc$ gcc gtod.c -o gtod
wu@ubuntu:~/linuxc$ ./gtod
sum = 999990000000000
the loop take 37713307 microsecond
the loop take 37.713307 second

可以看出,嵌套for循环运行了约37.7s

参考资料

http://lib.csdn.net/article/operatingsystem/23094#focustext

http://blog.csdn.net/coloriy/article/details/49510401

如果文章对您有帮助,欢迎点击下方按钮打赏作者

Comments

No comments yet.
To verify that you are human, please fill in "七"(required)