printf(―send signal to child process (%d) \\n‖,pid); sleep(1);
kill(pid ,SIGABRT); wait(&status);
if(WIFSIGNALED(status))
printf(―chile process receive signal %d\\n‖,WTERMSIG(status)); } }
4.2 signal(设置信号处理方式)
表头文件 #include
定义函数 void (*signal(int signum,void(* handler)(int)));
函数说明 signal()会依参数signum 指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行。如果参数handler不是函数指针,则必须是下列两个常数之一:
SIG_IGN 忽略参数signum指定的信号。
SIG_DFL 将参数signum 指定的信号重设为核心预设的信号处理方式。 返回值 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明 在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此操作请改用sigaction()。 5. 进程调度
5.1 getpriority(取得程序进程执行优先权)
表头文件 #include
定义函数 int getpriority(int which,int who);
函数说明 getpriority()可用来取得进程、进程组和用户的进程执行优先权。 参数 which有三种数值,参数who 则依which值有不同定义 which
who 代表的意义
PRIO_PROCESS who 为进程ID PRIO_PGRP PRIO_USER
who 为进程的组ID who 为用户ID
此函数返回的数值介于-20 至20之间,代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。
返回值 返回进程执行优先权,如有错误发生返回值则为-1 且错误原因存于errno。 附加说明 由于返回值有可能是-1,因此要同时检查errno是否存有错误原因。最好在调用次函数前先清除errno变量。
错误代码 ESRCH 参数which或who 可能有错,而找不到符合的进程。EINVAL 参数which 值错误。
5.2 setpriority(设置程序进程执行优先权)
表头文件 #include
定义函数 int setpriority(int which,int who, int prio);
函数说明 setpriority()可用来设置进程、进程组和用户的进程执行优先权。参数which有三种数值,参数who 则依which值有不同定义
参数prio介于-20 至20 之间。代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。此优先权默认是0,而只有超级用户(root)允许降低此值。 返回值 执行成功则返回0,如果有错误发生返回值则为-1,错误原因存于errno。 ESRCH 参数which或who 可能有错,而找不到符合的进程 EINVAL 参数which值错误。 EPERM 权限不够,无法完成设置 EACCES 一般用户无法降低优先权 5.3 nice(改变进程优先顺序)
表头文件 #include
函数说明 nice()用来改变进程的进程执行优先顺序。参数inc数值越大则优先顺序排在越后面,即表示进程执行会越慢。只有超级用户才能使用负的inc 值,代表优先顺序排在前面,进程执行会较快。
返回值 如果执行成功则返回0,否则返回-1,失败原因存于errno中。 错误代码 EPERM 一般用户企图转用负的参数inc值改变进程优先顺序。 6. 其他
6.1 atexit(设置程序正常结束前调用的函数)
表头文件 #include
定义函数 int atexit (void (*function)(void));
函数说明 atexit()用来设置一个程序正常结束前调用的函数。当程序通过调用exit()或从main中返回时,参数function所指定的函数会先被调用,然后才真正由exit()结束程序。 返回值 如果执行成功则返回0,否则返回-1,失败原因存于errno中。 范例 #include
printf(―before exit () !\\n‖); } main() {
atexit (my_exit); exit(0); }
6.2 exit(正常结束进程)
表头文件 #include
函数说明 exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。
实验要求:
1. 编写一个程序,打印进程的如下信息:进程标识符,父进程标识符,真实用户ID,有效
用户ID,真实用户组ID,有效用户组ID。并分析真实用户ID和有效用户ID的区别。 2. 阅读如下程序:
/*
process using time */
#include
#include
void time_print(char *,clock_t);
int main(void) { }
void time_print(char *str, clock_t time) { }
编译并运行,分析进程执行过程的时间消耗(总共消耗的时间和CPU消耗的时间),并
long tps = sysconf(_SC_CLK_TCK); printf(―%s: %6.2f secs\\n‖,str,(float)time/tps); exit(EXIT_SUCCESS); puts(―child times‖);
time_print(―\\tuser CPU‖,t_end.tms_cutime); time_print(―\\tsys CPU‖,t_end.tms_cstime); time_print(―elapsed‖,end-start); puts(―parent times‖);
time_print(―\\tuser CPU‖,t_end.tms_utime); time_print(―\\tsys CPU‖,t_end.tms_stime); clock_t start,end; struct tms t_start,t_end; start = times(&t_start);
system(―grep the /usr/doc/*/* > /dev/null 2> /dev/null‖); end=times(&t_end);
解释执行结果。再编写一个计算密集型的程序替代grep,比较两次时间的花销。注释程序主要语句。 3. 阅读下列程序:
/* fork usage */ #include
int main(void) { }
编译并多次运行,观察执行输出次序,说明次序相同(或不同)的原因;观察进程ID,分析进程ID的分配规律。总结fork()的使用方法。注释程序主要语句。 4. 阅读下列程序:
/* usage of kill,signal,wait */
pid_t child;
if((child=fork())==-1{
perror(―fork‖); exit(EXIT_FAILURE);
}else if(child==0){
puts(―in child‖);
printf(―\\tchild pid = %d\\n‖,getpid()); printf(―\\tchild ppid = %d\\n‖,getppid()); exit(EXIT_SUCCESS);
}else{ }
exit(EXIT_SUCCESS);
puts(―in parent‖);
printf(―\\tparent pid = %d\\n‖,getpid()); printf(―\\tparent ppid = %d\\n‖,getppid());