unix高级环境编程 例子 代码实现练习 第八章:进程控制

程序清单 8-1 fork函数示例 P173

/**
 * 程序清单 8-1 fork函数示例 P173
 *
 * zy:
 * 在下面的代码中,
 * 关键是区分好
 * 父进程执行的部分
 * 子进程执行的部分
 * 父、子进程都执行的部分
 *
 * 父进程和子进程谁先进程是不确定的。
 */

#include "apue.h"
#include "error.c"

int glob=6;
char buf[]="a write to stdout\n";

int main(int argc, char **argv) {
	int var;
	pid_t pid;

	var = 88;
	if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1){
		err_sys("write error");
	}
	printf("before fork\n");
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid==0) {//child
		glob++;
		var++;
	}else {//parent,休眠两秒,所以
		sleep(2);
	}
	printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);

}
结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out 
a write to stdout
before fork
pid=3305,glob=7,var=89
pid=3304,glob=6,var=88
asd@asd-desktop:~/workspace/test/src$ 

程序清单 8-2 vfork函数示例 P177

/**
 * 程序清单 8-2 vfork函数示例 P177
 *
 * zy:
 * 关键就是:
 * 产生的子进程的目地是在exec一个新程序
 * 产生的子进程不会将父进程的地址空间完全复制,
 * 在调用exec或者exit之前会直接在父进程的空间内运行,所以就会改变父进程的值
 *
 * 并且vfork产生的子进程保证了子进程先进程,
 * 在子进程调用了exec或者exit之后才会,父进程才得到调用
 */

#include "apue.h"
#include "error.c"

int glob=6;

int main(int argc, char **argv) {
	int var;
	pid_t pid;

	var = 88;
	printf("before fork\n");
	if((pid=vfork())<0){
		err_sys("fork error");
	}else if (pid==0) {//child
		glob++;
		var++;
		_exit(0);//为什么是这个请看177页
	}
	/**
	 * 只有父进程才会在这里进程
	 */
	printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);
	exit(0);
}
结果:

asd@asd-desktop:~/workspace/test/src$ gcc test.c 
asd@asd-desktop:~/workspace/test/src$ ./a.out 
before fork
pid=3395,glob=7,var=89
asd@asd-desktop:~/workspace/test/src$ 

程序清单 8-3 打印exit状态的说明 P180

/**
 * 程序清单 8-3 打印exit状态的说明 P180
 *
 * zy:
 * 背景是这样,
 * 如果子进程终止了,无论异常还是正常的,
 * 那么内核就会通过给父进程发送SIGCHLD信号
 * 父进程可以调用wait和waitpid这个两个函数获得子进程结束的状态,
 * 如果父进程收到SIGCHLD之后调用wait,那么可以立刻返回,获得子进程结束的状态
 * 如果父进程在任意时刻调用wait,那么会堵塞,直接接受到SIGCHLD信号,然后拿到子进程结束的状态
 *
 * 这个8-3的代码就是写一个函数
 * 传入子进程结束的状态
 * 就打印出一些信息,供我们判断。
 */

#include "apue.h"
#include "error.c"
#include <sys/wait.h>

void pr_exit(int status){
	printf("status: %d",status);
	if(WIFEXITED(status)){//如果是子进程正常返回,该判断为真
		printf("normal termination, exit status = %d \n",
				WEXITSTATUS(status));//取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
	}else if (WIFSIGNALED(status)) {//如果子进程是异常返回,则为真
		printf("abnormal termination, signal number = %d %s \n",
				WTERMSIG(status),//取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
#ifdef WCOREDUMP
	WCOREDUMP(status)?"(croe file generated )": " "
#else
			 " ");
#endif
	}else if(WIFSTOPPED(status))//若为当前暂停子进程的返回的状态,则为真
		printf("child stopped,signal number = %d\n",WSTOPSIG(status));

}


程序清单 8-4 演示不同的exit值 P181

/**
程序清单 8-4 演示不同的exit值 P181
 
zy:
同时,我们也演示了wait函数,
注意,调用wait函数后,我们将等待子进程返回,
拿到状态后,我们再用pr_exit来打印其状态信息


 */
#include "apue.h"
#include "error.c"
#include <sys/wait.h>

void pr_exit(int status){
	printf("status: %d",status);
	if(WIFEXITED(status)){//如果是子进程正常返回,该判断为真
		printf("normal termination, exit status = %d \n",
				WEXITSTATUS(status));//取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
	}else if (WIFSIGNALED(status)) {//如果子进程是异常返回,则为真
		printf("abnormal termination, signal number = %d %s \n",
				WTERMSIG(status),//取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
#ifdef WCOREDUMP
	WCOREDUMP(status)?"(croe file generated )": " "
#else
			 " ");
#endif
	}else if(WIFSTOPPED(status))//若为当前暂停子进程的返回的状态,则为真
		printf("child stopped,signal number = %d\n",WSTOPSIG(status));

}
int main(void){
	pid_t pid;
	int status;
	if((pid=fork())<0){
		err_sys("fork error");
	}else if( pid==0){//child
		exit(7);
	}
	if(wait(&status)!=pid){
		err_sys("wait error");
	}
	pr_exit(status);
	
	if((pid=fork())<0){
		err_sys("fork error");
	}else if( pid==0){//child
		abort();
	}
	if(wait(&status)!=pid){
		err_sys("wait error");
	}
	pr_exit(status);
	
	if((pid=fork())<0){
		err_sys("fork error");
	}else if( pid==0){//child
		status/=0;
	}
	if(wait(&status)!=pid){
		err_sys("wait error");
	}
	pr_exit(status);
	
	exit(0);
}


结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out 
status: 1792normal termination, exit status = 7 
status: 134abnormal termination, signal number = 6   
status: 136abnormal termination, signal number = 8   
asd@asd-desktop:~/workspace/test/src$ 

程序清单 8-5 调用fork两次以避免僵尸进程 P183

/**
 * 程序清单 8-5 调用fork两次以避免僵尸进程 P183
 *
 * zy:
 * 首先要明白什么是僵尸进程
 * 也就是就是一个虽然已经终止的子进程,但是父进程没有回收其资源的
 * 就是僵尸进程。
 *
 * 我们这里避免成为僵尸进程的办法其实就是
 * 让init进程变为一个子进程的父进程,这样就是可以由init进程完全其回收资源等工作
 *
 */

#include "apue.h"
#include "error.c"
#include <sys/wait.h>
int main(){
	pid_t pid;
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		if((pid=fork())<0){
			err_sys("fork error");
		}else if(pid>0){//这是第一孩子,也是第二个孩子的父亲
			exit(0);
		}
		//第二个孩子执行这一段代码
		//由于第二个孩子的父亲,也就是第一个孩子自己exit了,所以其父进程很快就会变成为init进程
		sleep(2);
		printf("我是第二个孩子,我们的父进程是:%d\n",getppid());
		exit(0);
	}
	//下面是第一个孩子的父进程执行的代码,这里是为了回收一个第一个孩子的资源
	if(waitpid(pid,NULL,0)!=pid){
		err_sys("waitpid error"); 
	}
	//下面我就可以在这里写第一个孩子,父进程的代码了,在这里它已经不是任何孩子的父亲了
	exit(0);
}

结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out 
asd@asd-desktop:~/workspace/test/src$ 我是第二个孩子,我们的父进程是:1

程序清单 8-6 具有竞争条件的程序 P186

/**
 * 程序清单 8-6 具有竞争条件的程序 P186
 *
 * zy:
 	由子进程和父进程各输出一段话,由于依赖于进程调度,包括顺序和运行时间
 	所以每次运行的结果都不是一样的。
 *
 */

#include "apue.h"
#include "error.c"

static void charatatime( char * str){
	char *ptr;
	int c;
	
	setbuf(stdout,NULL);//设置其没有缓冲
	for(ptr=str;(c= *ptr++)!=0;){//设置其一个字符一个字符的打
		putc(c,stdout);
	}
}

int main(){
	pid_t pid;
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		charatatime("output from child\n");
	}else{
		charatatime("output from parent\n");
	}
}

结果:

asd@asd-desktop:~/workspace/test/src$ gcc test.c
asd@asd-desktop:~/workspace/test/src$ ./a.out 
outputou tfpruotm  fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out 
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out 
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out 
outpuotu tfpruotm  fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out 
outpuotu tfpruotm  fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out 
outputo uftrpoumt  pfarroemn tc
hild
asd@asd-desktop:~/workspace/test/src$ 
asd@asd-desktop:~/workspace/test/src$ ./a.out 
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out 
outpuotu tfpruotm  fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ 

程序清单 8-7 修改程序清单8-6以避免竞争条件

/**
 * 程序清单 8-7 修改程序清单8-6以避免竞争条件
 *
 * zy:
 * 我们主要使用了tell wait、wait parent等一系列函数
 * 这些函数都不能理解
 * 顾名思义即可
 * 以后会具体分析其实现方法
 * 
 * 所以该代码现在还不能运行,因为现在还没有现实嘛,先放在这里吧
 *
 */


#include "apue.h"
#include "error.c"
#include "apue.h"


static void charatatime( char * str){
	char *ptr;
	int c;
	
	setbuf(stdout,NULL);//设置其没有缓冲
	for(ptr=str;(c= *ptr++)!=0;){//设置其一个字符一个字符的打
		putc(c,stdout);
	}
}


int main(){
	pid_t pid;
	TELL_WAIT();
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		WAIT_PARENT();
		charatatime("output from child\n");
	}else{
		charatatime("output from parent\n");
		TELL_CHILD(pid);
	}
}

程序清单 8-7 exec函数实例

/**
 * 程序清单 8-7 exec函数实例 P191
 *
 * zy:
 * 我们用子进程去执行echoall.out程序,这个程序也是我们自己写的,是程序清单8-9
 * 其中参数有个关键就是(char *) 0之前表示参数结束
 *
 * 下面这段程序的execlp部分能够正常执行的,也就是能够正常执行echoall.out这个函数
 * 但是execle部分是没有成功执行的,我也没有查出原因
 * 如果我对第一个参数传入:/home/asd/workspace/test/src/的话,得到的错误是:Permission denied
 *
 * 但是如果我传入/home/asd/workspace/test/src/echoall.out,得到的错误又将是:Bad address
 *
 */

#include "error.c"
#include "apue.h"
#include "sys/wait.h"

char *env_init[]={"USER=unknown","PATH=/tmp",NULL};

int main(){
	pid_t pid;
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		if(execle("/home/asd/workspace/test/src/echoall.out","echoall.out","myarg1","MY_ARG2","(char *)0",env_init)<0){
			err_sys("execle error");
		}
	}
	if(waitpid(pid,NULL,0)<0){
		err_sys("wait error");
	}

	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		if(execlp("./echoall","echoall","only 1 arg",(char *)0)<0){
			err_sys("execlp error");
		}
	}
	exit(0);
}

程序清单 8-9 回送所有命令行参数和所有环境字符串 P192

/**
程序清单 8-9 回送所有命令行参数和所有环境字符串 P192
 
zy:
这个程序是被8-8所执行的echoall.out,没有什么特别的
只是回送了所有的参数和环境变量

 */
#include "apue.h"
#include "error.c"

int main(int argc, char **argv) {
	int i;
	char **ptr;
	extern char **environ;
	
	for(i=0;i<argc;i++){
		printf("agrv[%d] : %s \n",i,argv[i]);
	}

	for(ptr=environ;*ptr!=0;ptr++){
		printf("%s\n",*ptr);
	}
	exit(0);
}

程序清单 8-10 执行一个解释器文件的程序

/**
 * 程序清单 8-10 执行一个解释器文件的程序 P197
 *
 * zy:
 * 出现的错误和8-9类似
 * 总是permission denied 似乎和机子有关
 *
 * 在这个题中,解释器的存在显得非常的简单,因解释器就是一个文本,文本里面放着要执行的程序
 *
 */

#include "error.c"
#include "apue.h"
#include "sys/wait.h"
int main(){
	pid_t pid;
	if((pid=fork())<0){
		err_sys("fork error");
	}else if (pid == 0){//first child
		if(execl("/home/asd/workspace/test/src/testinterp","testinterp","myarg1","MY_ARG2","(char *)0")<0){
			err_sys("execle error");
		}
	}
	if(waitpid(pid,NULL,0)<0){
		err_sys("wait error");
	}
	exit(0);
}

程序清单 8-11 作为解释器文件的awk程序

基本上不太明白这段代码是怎么回事,搞了半天好像也不是c代码

程序清单 8-12 system函数(没有信号处理)P200

/**
 * 程序清单 8-12 system函数(没有信号处理)P200
 *
 * zy:
 * system函数在代码中调用的时候就是说:相当于在终端输入一些命令
 * 产生的结果方便在代码中使用
 */
#include "sys/wait.h"
#include "error.c"
#include "apue.h"
#include "unistd.h"
#include <errno.h>

int mySystem(const char * cmdstring){
	pid_t pid;
	int status;

	if(cmdstring==NULL){
		return(1);
	}
	if((pid=fork())<0){
		status=-1;
	}else if(pid==0){//child
		execl("/bin/sh","sh","-c",cmdstring,(char *)0);
		_exit(127);
	}else{//parent
		while(waitpid(pid,&status,0)<0){
			if(errno!=EINTR){
				status=-1;
				break;
			}
		}
	}
	return status;
}

int main(){
	mySystem("date");
}


程序清单 8-13 调用system函数P201

/**
 * 程序清单 8-13 调用system函数P201
 *
 * zy:
 * 这是一段代码用于测试8-12所写的system函数
 */




#include "sys/wait.h"
#include "error.c"
#include "apue.h"
#include "unistd.h"
#include <errno.h>


int mySystem(const char * cmdstring){
	pid_t pid;
	int status;


	if(cmdstring==NULL){
		return(1);
	}
	if((pid=fork())<0){
		status=-1;
	}else if(pid==0){//child
		execl("/bin/sh","sh","-c",cmdstring,(char *)0);
		_exit(127);
	}else{//parent
		while(waitpid(pid,&status,0)<0){
			if(errno!=EINTR){
				status=-1;
				break;
			}
		}
	}
	return status;
}
int main(int argc, char **argv) {
	int status;
	if((status=mySystem("date"))<0){
		err_sys("system() error");
	}
	//pr_exit(status);这个好像以后才实现,现在还没实现呢
	if((status=mySystem("nosuchcommmand"))<0){
		err_sys("system() error");
	}
	//pr_exit(status);
	if((status=mySystem("who;exit 44"))<0){
		err_sys("system() error");
	}
	//pr_exit(status);
	exit(0);
}
结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out 
Mon Mar 10 21:55:03 CST 2014
sh: 1: nosuchcommmand: not found
asd      tty7         2014-03-10 18:52
asd      pts/0        2014-03-10 21:41 (:0.0)
asd@asd-desktop:~/workspace/test/src$

 程序清单 8-14 用system执行命令行参数

/**
 * 程序清单 8-14 用system执行命令行参数
 *
 * zy:
 * 这个本身没什么,主要是和8-15配合
 */
#include "error.c"
#include "apue.h"

int main(int argc, char **argv){
	int status;

	if(argv<2)
		err_quit("command-line argument required");

	if((status=system(argv[1]))<0)
		err_sys("system ()error");
	//pre_exit(status);//暂时没找到这个代码的实现处
}

程序清单 8-15 打印实际和有效用户ID P203

/**
 * 程序清单 8-15 打印实际和有效用户ID P203
 *
 * zy:
 * 这里主要是讲一个漏洞,
 * 当我们让给予了8-14的程序超级用户权限时,
 * 其在system函数中执行的fork和exec也具有超级用户的权限
 *
 * 为了预防这样的情况,我们应该直接调用fork和exec,而不要调用system函数
 */




#include "error.c"
#include "apue.h"


int main() {
	printf("real uid=%d, efffective uid =%d \n",getuid(),geteuid());
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./tsys /home/asd/printuids 
real uid=1000, efffective uid =1000 
asd@asd-desktop:~/workspace/test/src$ su
Password: 
root@asd-desktop:/home/asd/workspace/test/src# chown root t
test2.c     test2.c~    test.c      test.c~     testinterp  tsys
root@asd-desktop:/home/asd/workspace/test/src# chown root tsys 
root@asd-desktop:/home/asd/workspace/test/src# chmod u+s tsys 
root@asd-desktop:/home/asd/workspace/test/src# ls -l tsys 
-rwsrwxr-x 1 root asd 7765 Mar 13 09:22 tsys
root@asd-desktop:/home/asd/workspace/test/src# exit
exit
asd@asd-desktop:~/workspace/test/src$ ./tsys /home/asd/printuids 
real uid=1000, efffective uid =0 


其中:chmod u+s

  • “为了方便普通用户执行一些特权命令,SUID/SGID程序允许普通用户以root身份暂时执行该程序,并在执行结束后再恢复身份。”
    chmod u+s 就是给某个程序的所有者以suid权限,可以像root用户一样操作。
请注意,我们使用了chown之后,tsys的所有者是root,然而我们又退出了root权限,在执行第二句:
./tsys /home/asd/printuids 
的时候,我们的身份是asd,那么为什么能够执行root所有者的程序,就是因为chmod u+s这个命令。
此外,我们可以看到在system函数中执行的fork和exec也具有超级用户的权限,预防这样的情况发生就是,不要使用system,而是使用fork和exec。

程序清单 8-16 产生会计数据的程序 P205

/**
 * 程序清单 8-16 产生会计数据的程序 P205
 *
 * zy:
 * 这主要是用于产生会计进程的数据
 * 这些数据将由另一个程序8-17调用,以供我们的观察
 *
 * 会计进程当进程结束时就会记录,可以用accton命令将其打开
 * 注意我的系统是linux,那么我的会计文件会产生在/var/account/pacct
 */


#include "error.c"
#include "apue.h"

int main() {
	pid_t pid;
	if((pid=fork())<0)
		err_sys("fork error");
	else if(pid!=0){//parent
		sleep(2);
		exit(2);
	}
					//first child
	if((pid=fork())<0)
		err_sys("fork error");
	else if(pid!=0){// first child as parent
		sleep(4);
		abort();
	}

					//second child
	if((pid=fork())<0)
		err_sys("fork error");
	else if(pid!=0){// second child as parent
		execl("/bin/dd","dd","if=//home/asd/Downloads/vimrc.zip","of=/dev/null",NULL);//dd就是一个复制的命令,后面两个参数应该不言而喻吧
		exit(7);
	}
					//third child
	if((pid=fork())<0)
		err_sys("fork error");
	else if(pid!=0){// third child as parent
		sleep(8);
		abort();
	}

					//fourth child
	sleep(6);
	kill(getpid(),SIGKILL);
	exit(6);
}

程序清单 8-17 用system执行命令行参数 P206

/**
 * 程序清单 8-17 用system执行命令行参数 P206
 *
 * zy:
 * 用这个程度去读会计文件,将我们需要的东西打印出来
 */
#include "error.c"
#include "apue.h"
#include <sys/acct.h>
#ifdef HAS_SA_STAT
#define FMT "%-*.*s e=%6ld, chars = %7ld, stat=%3u: %c %c %c %c\n"	//%-*.*s翻K&R的书136页,-表示左对齐,
																	//第一个*字符串总共多长
																	//第二个*表示占占多长
#else
#define FMT "%-*.*s e=%6ld, chars = %7ld, %c %c %c %c\n"
#endif
#ifndef HAS_ACORE
#define ACORE 0
#endif
#ifndef HAS_AXSIG
#define AXSIG 0
#endif

static unsigned long compt2ulong(comp_t comptime){	//将comp_t格式转化为unsign long的形式
													//long形式之后的数字是就墙上时钟时间,以每秒滴答数为单位测量
	unsigned long val;
	int exp;

	val=comptime & 0x1fff;
	exp=(comptime >> 13 )& 7;
	while(exp -- >0)
		val*=8;
	return(val);
}
int main(int argc, char **argv){
	struct acct acdata;
	FILE *fp;

	if(argc!=2)
		err_quit("usage:pracct filename");

	if((fp=fopen(argv[1],"r"))==NULL){
		err_sys("can't open %s ",argv[1]);
	}
	while(fread(&acdata,sizeof(acdata),1,fp)==1){
		printf(FMT,
				(int)sizeof(acdata.ac_comm),	//command name 就是程序名
				(int)sizeof(acdata.ac_comm),
				acdata.ac_comm,					//这个是字符串,那上面两个是打印什么的
				compt2ulong(acdata.ac_etime),	//elapsed tiem
				compt2ulong(acdata.ac_io),		//传输的字节数,包括read和write
#ifdef HAS_SA_STAT
				(unsigned char)acdata.ac_stat,	//终止状态
#endif
				acdata.ac_flag & ACORE ?'D':' ',//进程转储core
				acdata.ac_flag & AXSIG ?'X':' ',//进程由信号杀死
				acdata.ac_flag & AFORK ?'F':' ',//进程是由fork产生
				acdata.ac_flag & ASU ?'S':' '	//进程使用超级用户模式
				);
	}
	if(ferror(fp))
		err_sys("read error");
	exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ accton on
Turning on process accounting, file set to the default '/var/log/account/pacct'.
accton: Operation not permitted
asd@asd-desktop:~/workspace/test/src$ ./a.out 
7+1 records in
7+1 records out
4074 bytes (4.1 kB) copied, 0.000168319 s, 24.2 MB/s
asd@asd-desktop:~/workspace/test/src$ accton off
Turning off process accounting.
accton: Operation not permitted
asd@asd-desktop:~/workspace/test/src$ sudo accton off
Turning off process accounting.
asd@asd-desktop:~/workspace/test/src$ gcc test.c
asd@asd-desktop:~/workspace/test/src$ ./a.out /var/log/account/pacct
�                e=  7350, chars =    7349,       S
                e=  7349, chars =    7333,        
                e=  7333, chars =    7327,        
                e=  7327, chars =    7326,        
,                e=  7326, chars =    7295,        
                 e=  7353, chars =    7352,        
                e=  7352, chars =    7351,        
Y1                e=  7351, chars =    7295,     F  
                e=  7354, chars =    7295,        
                e=  7355, chars =    7295,        
                e=  7356, chars =    7295,        
o$                e=  7295, chars =    7294,       S
8                e=  7294, chars =    7132,       S
�%                e=  7358, chars =    7357,        
                e=  7359, chars =    7357,        
                e=  7360, chars =    7357,        
                e=  7361, chars =    7357,        
                e=  7362, chars =    7357,        
k'                e=  7357, chars =    2261,        
x                e=  7365, chars =    7363,        
l                e=  7366, chars =    7363,        
0                e=  7368, chars =    1724,     F  
p                e=  7373, chars =    7371,        
                e=  7371, chars =    7369,        
�%                e=  7374, chars =    7369,        
�(                e=  7367, chars =    7363,        
                e=  7363, chars =    2261,        
                e=  7375, chars =    7369,        
                e=  7376, chars =    7369,        
                e=  7377, chars =    7369,        
�                e=  7378, chars =    7132,        
�                e=  7379, chars =    7132,        
0                e=  7380, chars =    1724,     F  
                e=  7382, chars =    7132,        
]*                e=  7381, chars =       1,        
                e=  7384, chars =    7132,        
$                e=  7387, chars =    7386,        
�                e=  7385, chars =    7132,        
1'                e=  7390, chars =    7040,       S
�                e=  7386, chars =       1,     F  
�                e=  7389, chars =    7388,     F  
2'                e=  7391, chars =    7242,       S
�                e=  7388, chars =       1,     F  
                e=  7392, chars =    7132,        
                  e=  7394, chars =    7393,    

可能和机子有关,我打印出来名字全是乱码,反正意思我大概懂了,书上讲的很清楚。

程序清单 8-18 时间以及执行所有命令参数 P209

/**
 * 程序清单 8-18 时间以及执行所有命令参数 P209
 *
 * zy:
 * 主要将times这个函数
 * 可以得到一个结构,结构里有各种时间
 * 比如用户cpu时间、系统cpu时间
 * 主要注意是需要记录两个时间,然后算差值
 */
#include "error.c"
#include "apue.h"
#include <sys/times.h>

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

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;

	printf("\ncommand: %s\n",cmd);
	if((start=times(&tmsstart))==-1)//times的返回值就是当前流逝的墙上时钟时间
		err_sys("times error");
	if((status=system(cmd))<0){
		err_sys("system() error");
	}
	if((end=times(&tmsend))==-1){//需要start和end两者相减得到运行的时间
		err_sys("times error");
	}

	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){//每秒的滴答数,我们用这个将滴答数转化为秒数
			err_sys("sysconf error");
		}
	}
	printf("\treal:\t%7.2f\n",real/(double)clktck);
	printf("\tuser:\t%7.2f\n",(tmsend->tms_utime-tmsstart->tms_utime)/(double)clktck);
	printf("\tsys :\t%7.2f\n",(tmsend->tms_stime-tmsstart->tms_stime)/(double)clktck);
	printf("\tchild user:\t%7.2f\n",(tmsend->tms_cutime-tmsstart->tms_cutime)/(double)clktck);
	printf("\tchild sys:\t%7.2f\n",(tmsend->tms_cstime-tmsstart->tms_cstime)/(double)clktck);

}



结果:

asd@asd-desktop:~/workspace/test/src$ ./a.out "sleep 5" "date"

command: sleep 5
	real:	   5.02
	user:	   0.00
	sys :	   0.00
	child user:	   0.00
	child sys:	   0.00

command: date
Thu Mar 13 12:00:57 CST 2014
	real:	   0.02
	user:	   0.00
	sys :	   0.00
	child user:	   0.00
	child sys:	   0.00
asd@asd-desktop:~/workspace/test/src$ 


其它问题的总结

关于如何使用gedit编码的插件

ubuntu12.04 获得su的密码

ubuntu 12.04 怎么取得超级用户权利

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值