一.实验目的
1.重温进程概念,理解Linux中的进程。
2.理解Linux中进程产生的方式,理解fork和clone的差别。
3.了解Linux中的线程。
二.实验内容
1.编制C程序,用fork()系统调用创建一个子进程。
2.使用clone()调用创建一个Linux子进程,子进程调用execvp执行系统命令ls。
三.实验步骤和结果
1、实验内容1:fork
(1)编写C程序fork_example.c
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
pid_t childpid;
int retval;
int status;
childpid = fork();
if(childpid>=0)
{
if (childpid==0)
{
printf("CHILD:I am the child process!\n");
printf("CHILD:Here's my PID:%d\n",getpid());
printf("CHILD:My parent's PID is:%d\n",getppid());
printf("CHILD:The value of fork return is:%d\n",childpid);
printf("CHILD:Sleeping for 1 second...\n");
sleep(1);
printf("CHILD:Enter an exit value(0 to 255):");
scanf("%d",&retval);
printf("CHILD:Goodbye!\n");
exit(retval);
}
else
{
printf("PARENT:I am the parent process!\n");
printf("PARENT:Here's my PID:%d\n",getpid());
printf("PARENT:The value of my child's PID is %d\n",childpid);
printf("PARENT:I will now wait for my child to exit.\n");
wait(&status);
printf("PARENT:Child's exit code is:%d\n",WEXITSTATUS(status));
printf("PARENT:Goodbye!\n");
exit(0);
}
}
else
{
perror("fork");
exit(0);
}
}
(2)使用命令cc -o fork_example fork_example.c编译
(3)编译成功后,使用命令./ fork_example运行,子进程的退出值输入3。运行结果如下图:
2.实验内容2:clone
(1)编写clone_example.c源文件
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <signal.h>
#define FIBER_STACK 8192
int lc=2019;
int do_something(){
printf("This is son, the pid is:%d, the lc is: %d\n", getpid(), lc);
lc=2020;
char* argv[] = {"ls", "-l", NULL}; // 构造 vector,注意argv[0] 是占用参数
if (execvp("ls", argv) == -1) { // 替换代码段和数据段,并重新从 ls 入口点执行
perror("exec");
}
exit(1);
}
int main() {
char * stack;
stack = (char*)malloc(FIBER_STACK);
if(!stack) {
printf("The stack failed\n");
exit(0);
}
printf("creating son thread!!!\n");
int cpid=clone(do_something, (char *)stack + FIBER_STACK, CLONE_VM|CLONE_VFORK, 0);
int pid=waitpid(cpid,0,0);
if (pid==0){
perror("waiting");
}
printf("This is father, my pid is: %d, the lc is: %d\n", getpid(), lc);
free(stack);
exit(1);
}
(2)使用命令cc -o clone_example clone_example.c编译
(3)编译成功后,使用命令./ clone_example运行。运行结果如下图:
该实验结果表明,成功通过clone创建了子进程,该子进程修改了变量lc的值,并且同时调用 execvp 执行系统命令 ls。父进程等待子进程执行完毕后,返回父进程的提示语句。
四.实验问题与分析
1、调用fork的进程叫做父进程,由此调用而产生的进程叫子进程。父进程返回的是子进程的pid,子进程从fork()返回的是0。
2、clone()系统调用中常见的flags参数:
(1)CLONE_FS。
如果使用这个标志的话,父进程和子进程文件系统信息,包括根目录、当前工作目录、umask等。
(2)CLONE_FILES。
如果使用这个标志的话,父进程和子进程共享文件描述符表。
(3)CLONE_SIGHAND。
如果使用这个标志的话,父进程和子进程共享信号处理函数表。
(4)CLONE_VM。
如果使用这个标志的话,那么父进程和子进程运行在同一个虚拟地址空间(确切地说,是使用同一个代码段和数据段,但不使用同一个堆栈)。
(5)CLONE_VFORK
如果使用这个标志的话,父进程被挂起,直至子进程释放虚拟内存资源
五.实验总结
本次实验,我首先重温了进程概念,理解Linux中的进程的含义。通过理解fork和clone的差别,分别用fork和clone来创建子进程。