实验七 Linux进程控制实验
学号:6130116217
专业班级:计算机科学与技术165班
课程名称:Linux程序设计实验
一、实验项目名称
Linux进程控制实验
二、实验目的
通过编写多进程程序和守护进程,熟练掌握fork()、exec()、wait()和waitpid()等函数的使用方法和守护进程的编写方法,并进一步理解在Linux中多进程编程方法。
三、实验基本原理
Linux进程控制
四、主要仪器设备及耗材
硬件: PC机;
软件:Windows OS,VMware,Fedora10.0或其他Linux发行版。
五、实验步骤
1. 编写c程序,要求程序运行时共有3个进程,其中一个为父进程,其余两个是该父进程创建的子进程,其中一个子进程运行“ls -l”指令,另一个子进程在暂停5s之后退出,父进程先用阻塞方式等待第一个子进程的结束,然后用非阻塞方式等待另一个子进程的退出,待收集到第二个子进程结束的信息,父进程就结束。
请问如下代码是否能实现上述要求,若不能请指出原因并对代码进行修改。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t child1, child2, child;
/*创建两个子进程*/
child1 = fork();
child2 = fork();
/*子进程1的出错处理*/
if (child1 == -1) {
printf("Child1 fork error\n");
exit(1);
} else if (child1 == 0) { /*在子进程1中调用execlp()函数*/
printf("In child1: execute 'ls -l'\n");
if (execlp("ls", "ls","-l", NULL)<0) {
printf("Child1 execlp error\n");
}
}
if (child2 == -1) { /*子进程2的出错处理*/
printf("Child2 fork error\n");
exit(1);
} else if( child2 == 0 ) { /*在子进程2中使其暂停5s*/
printf("In child2: sleep for 5 seconds and then exit\n");
sleep(5);
exit(0);
} else { /*在父进程中等待两个子进程的退出*/
printf("In father process:\n");
child = waitpid(child1, NULL, 0); /* 阻塞式等待 */
if (child == child1) {
printf("Get child1 exit code\n");
} else {
printf("Error occured!\n");
}
do {
child =waitpid(child2, NULL, WNOHANG);/* 非阻塞式等待 */
if (child == 0) {
printf("The child2 process has not exited!\n");
sleep(1);
}
} while (child == 0);
if (child == child2) {
printf("Get child2 exit code\n");
} else {
printf("Error occured!\n");
}
}
exit(0);
}
答:不能实现要求,当执行代码child1 = fork() 时,child1 = 0,当执行代码child2 = fork()时,将复制父进程的内存(此时父进程中child1 =0,即父进程为child1进程),所以在child2所代表进程中child1 = 0,将执行ls -l 命令。所有代码将执行两次ls -l命令。
修改后代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <syspes.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t child1, child2, child;
/*创建两个子进程*/
child1 = fork();
if (child1 == -1) {
printf("Child1 fork error\n");
exit(1);
} else if (child1 == 0) { /*在子进程1中调用execlp()函数*/
printf("In child1: execute 'ls -l'\n");
if (execlp("ls", "ls","-l", NULL)<0) {
printf("Child1 execlp error\n");
}
} else {
child2=fork();
if (child2 == -1) { /*子进程2的出错处理*/
printf("Child2 fork error\n");
exit(1);
} else if( child2 == 0 ) { /*在子进程2中使其暂停5s*/
printf("In child2: sleep for 5 seconds and then exit\n");
sleep(5);
exit(0);
} else { /*在父进程中等待两个子进程的退出*/
printf("In father process:\n");
child = waitpid(child1, NULL, 0); /* 阻塞式等待 */
if (child == child1) {
printf("Get child1 exit code\n");
} else {
printf("Error occured!\n");
}
do {
child =waitpid(child2, NULL, WNOHANG);/* 非阻塞式等待 */
if (child == 0) {
printf("The child2 process has not exited!\n");
sleep(1);
}
} while (child == 0);
if (child == child2) {
printf("Get child2 exit code\n");
} else {
printf("Error occured!\n");
}
}
}
}
运行结果:
2. 调试教材例6.7、6.10程序
①例6.7
/*6-7.c 程序:通过宏WIFEXITED(stat_val),取得子进程exit(3)返回的结束代码*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid == 0) {
int i;
for (i = 3; i > 0; i--) {
printf("This is the child\n");
sleep(1);
}
exit(3);
} else {
int stat_val;
waitpid(pid, &stat_val, 0);
if (WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else if (WIFSIGNALED(stat_val))
printf("Child terminated abnormally, signal %d\n",
WTERMSIG(stat_val));
}
return 0;
}
编译运行
②例6.10
/*6-10.c 程序:守护进程和它的子进程退出信息写入系统日志文件*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<syslog.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/stat.h>
int main() {
pid_t child1,child2;
int i;
child1=fork();
if(child1>0) /*(1)创建子进程,终止父进程*/
exit(0); /*这是第一子进程,后台继续执行*/
else if(child1< 0) {
perror("创建子进程失败"); /*fork 失败,退出*/
exit(1);
}
setsid(); /*(2)在子进程中创建新会话*/
chdir("/"); /*(3)改变工作目录到“/”*/
umask(0); /*(4)重设文件创建掩码*/
for(i=0; i< NOFILE; ++i) /*(5)关闭文件描述符*/
close(i);
openlog("例6-10 程序信息",LOG_PID,LOG_DAEMON);/* 调用openlog 函数打开日志文件
*/
child2=fork();
if(child2==-1) {
perror("创建子进程失败"); /*fork 失败,退出*/
exit(1);
} else if(child2==0) {
syslog(LOG_INFO,"第二子进程暂停5 秒!"); /* 调用syslog,写入系统日志*/
sleep(5); /*睡眠5 秒钟*/
syslog(LOG_INFO,"第二子进程结束运行。");/* 调用syslog,写入系统日志*/
exit(0);
} else { /* 返回值大于0 代表父进程,这是第二子进程的父进程,即第一子进程*/
waitpid(child2,NULL,0); /*第一子进程调用waitpid 函数,等待第二子进程*/
syslog(LOG_INFO, "第一子进程在等待第二子进程结束后,也结束运行。");
closelog(); /*调用closelog,关闭日志服务*/
while(1) { /*无限循环*/
sleep(10); /*睡眠10 秒钟*/
}
}
}
编译运行
等待一段时间,查看/var/log/messages文件最后三行
六、实验数据及处理结果
七、思考讨论题
(1)如何用ps命令查看某个进程是否为守护进程?
答:执行代码ps -aux 可以查看守护进程
(2)如何结束一个守护进程?
答:ps -aux 查看守护进程pid
结束守护进程:kill -9 pid
八、参考资料
1.金国庆等,Linux程序设计(第二版),浙江大学出版社,2014年4月
2. Neil Matthew,《Linux程序设计》(第4版), 人民邮电出版社,2014年9月
3. 杨宗德,《Linux高级程序设计》(第三版),人民邮电出版社,2012年11月
4. Daniel P.,《深入理解Linux内核》(第三版),中国电力出版社,2013年1月