用户标识和进程调度

    任一进程都可以得到其实际用户 ID 和有效 ID 及组 ID。但有时希望找到运行该程序用户的的登录名。通常情况下可以调用 getpwuid(getuid()) 来得到,但如果一个用户有多个登录名,这些登录名又对应着同一个用户 ID(但登录 shell 不同)时,就可以考虑使用 getlogin 函数来获取此登录名。
#include <unistd.h>
char *getlogin(void);
                 /* 返回值:若成功,返回指向登录名字符串的指针;否则,返回 NULL */

    如果调用此函数的进程没有连接到用户登录时所用的终端,则函数会失败。通常称这些进程为守护进程(daemon)。
    给出了登录名,就可用 getpwnam 在口令文件中查找用户的相应记录,从而确定其登录 shell 等。

    UNIX 系统历史上对进程提供的只是基于调度优先级的粗粒度的控制。进程可以通过增大 nice 值选择以更低优先级运行,而只有特权进程允许提高调度权限。Single UNIX Specification 中 nice 值的范围在 0~2*NZERO-1 之间,有些实现支持 0~2*NZERO(注意:定义 NZERO 的头文件因系统而异。Linux 3.2.0 还可以通过非标准的 sysconf 参数 _SC_NZERO 来访问 NZERO 值)。
    进程可以通过 nice 函数获取或更改它的 nice 值,但无法影响任何其他进程的 nice 值。
#include <unistd.h>
int nice(int incr);
                   /* 返回值:若成功,返回新的 nice 值或 NZERO;否则,返回 -1 */

    incr 参数被增加到调用进程的 nice 值上。如果它过大或过小,系统都会无声无息地把它降到最大合法值或提高到最小合法值。由于 -1 是合法的成功返回值,所以在调用 nice 函数之前需要清除 errno,在 nice 返回 -1 时需要检查它的值,以便确认是否是调用失败。
    getpriority 函数也可以获取进程的 nice 值,还可以获取一组相关进程的 nice 值;setpriority 函数则可以为进程、进程组和属于特定用户 ID 的所有进程设置优先级。
#include <sys/resource.h>
int getpriority(int which, id_t who);
          /* 返回值:若成功,返回 -NZERO~NZERO-1 之间的 nice 值;否则,返回 -1 */
int setpriority(int which, id_t who, int value);
         /* 返回值:若成功,返回 0;否则,返回 -1 */

    其中,which 参数可以取以下 3 个值之一:PRIO_PROCESS 表示进程,PRIO_PGRP 表示进程组,PRIO_USER 表示用户 ID。如果 which 作用于多个进程,则返回其中优先级最高的(最小的 nice 值)。who 参数选择感兴趣的一个或多个进程。如果 who 为 0,表示调用进程、进程组或者用户(取决于 which 参数的值)。value 参数会增加到 NZERO 上,然后变为新的 nice 值。
    下面这个程序度量了调度进程 nice 值的效果:两个进程并行运行,各自增加自己的计数器。父进程使用了默认的 nice 值,子进程以调整后的 nice 值运行 10s 后,两个进程都打印各自的计数器并终止。通过比较不同 nice 值的进程的计数值的差异就可以了解 nice 值是如何影响进程调度的。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>

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);	// disabled the buffer on stdout
#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;		// run for 10 seconds

	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)
			printf("child set scheduling priority error\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 quit\n", s);
			exit(2);
		}
		checktime(s);
	}
}

    执行程序两次:一次用默认的 nice 值,另一次用最高有效 nice 值(最低调度优先级)。程序运行在单处理器 Linux 系统上,以显示调度程序如何在不同 nice 值的进程间进行 CPU 的共享。否则,对于有空闲资源的系统(如多处理器系统或多核 CPU),两个进程可能无需共享 CPU(运行在不同的处理器上),就无法看出具有不同 nice 值的两个进程的差异。
$ ./niceDemo.out                  # 默认 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 = 125786180
child count = 125607852           # 可见同父进程平等调度

$ ./niceDemo.out 20               # 最高 nice 值
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 = 229924425
child count = 3317494              # 可见 CPU 占比远低于父进程

猜你喜欢

转载自aisxyz.iteye.com/blog/2393327