- 实验目的:
- 理解进程的概念
- 掌握进程复制函数fork的用法
- 掌握替换进程映像exec函数族
- 掌握守护进程的创建步骤和使用。
1.用进程相关API 函数编程一个程序,使之产生一个进程扇:父进程产生一系列子进程,每个子进程打印自己的PID 然后退出。要求父进程最后打印PID。
这个实验让我深刻了解操作系统创建进程的模样,操作系统创建进程是以树的形式创建的 。以某个存在的进程作为树根开始,一级一级往下创建。实验如图:
仔细看好进程id,这是bash的进程号。
如图,以当前执行的bash为根,为可执行文件创建的子进程号为8239(这里可以当作第一父进程,实际上最顶级的进程号是bash进程),接着8239又创建了8240,8241这两个子进程,然后8240 又创建了8242子进程。
这就是一个进程树,而且通常新创建的pid都是加一的。
实验中使用wait是让父进程先暂时阻塞,等待子进程的结束,收集子进程执行信息/状况。具体可参考博客:
https://www.cnblogs.com/king-77024128/articles/2684317.html
加个exit的区别,参考 https://www.cnblogs.com/dongguolei/p/8098181.html。
2.用进程相关API 函数编写一个程序,使之产生一个进程链:父进程派生一个子进程后,然后打印出自己的PID,然后退出,该子进程继续派生子进程,然后打印PID,然后退出,以此类推。
递归写法:
逆序打印:逆序打印的思路和平常打印不同,要做到逆序就需要让每个父进程要保持住不能让它退出,如图:
当p1生出p2的时候,p1作为父亲不能退出,然后p2作为父亲生出p3,同理p2作为父亲也要保持住,这样等p3退出时,作为父亲的进程全部打印自己的pid,挨个退出,这样就形成了逆序。
实验结果:
可以看到,一旦设置了阻塞,那么充当父进程后暂时是阻塞的,这就是为什么按下三次回车才有结果显示,当最后一个进程只作为孩子的时候,还是要跑一次代码,所以需要再输入3,但最后一个进程将不执行循环的代码,直接退出(i的值是3不符合循环条件),子进程退出,立马呈现结果。
3.编写程序execl.c,实现父进程打印自己的pid号,子进程调用execl函数,用可执行程序file_creat替换本进程。注意命令行参数。
/*execl.c*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
/*判断入参有没有传入文件名*/
if(argc<2)
{
perror("you haven,t input the filename,please try again!\n");
exit(EXIT_FAILURE);
}
pid_t result;
result=fork();
if(result>0)
{
printf(“I’m parent,my pid:%d, mysun’s pid %d\n”,getpid(), result);
}
/* 下面代码是调用ls程序, 用可执行程序ls替换本进程
if(result==0)
{
printf(“I’m sum process my pid is %d\n”,getpid());
if(execl("/bin/ls","ls","-l",NULL)<0)
{
perror("execlp error");
}
}*/
/*下面程序调用execl函数,用可执行程序file_creat替换本进程*/
if(result==0)
{
printf(“I’m sum process my pid is %d\n”,getpid()); if(execl("./file_creat","file_creat",argv[1],NULL)<0)
perror("execl error!");
}
}
其中file_creat.c的 代码如下:
file_creat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void create_file(char *filename)
{
/*创建的文件具有可读可写的属性*/
if(creat(filename,0666)<0)
{
printf("create file %s failure!\n",filename);
exit(EXIT_FAILURE);
}
else
{
printf("create file %s success!\n",filename);
}
}
int main(int argc,char *argv[])
{
/*判断入参有没有传入文件名 */
if(argc<2)
{
perror("you haven't input the filename,please try again!\n");
exit(EXIT_FAILURE);
}
create_file(argv[1]);
exit(EXIT_SUCCESS);
}
4.编写守护进程,参考守护进程模版代码daemon.c,实现每隔2秒中向系统日志文件/var/log/syslog中写入字符串“I am a daemonAAA!”,可使用下面的接口函数:
openlog("daemon_test", LOG_CONS | LOG_PID, LOG_DAEMON);
syslog(LOG_DAEMON, "I am a daemonAAA!");
创建步骤:
1)父进程中执行fork后,执行exit退出;
2)在子进程中调用setsid;(脱离控制台)
3)让根目录“/”成为子进程的工作目录;
4)把子进程的umask变为0;
5)关闭任何不需要的文件描述符。
守护进程创建成功。