《Linux编程基础》黑马程序员/编著 清华大学出版社
目录
1、编写程序,在程序中创建一个子进程,使父子进程分别打印不同的内容。
2、编写程序,在程序中创建一个子进程,使子进程通过exec更改代码段,执行cat命令。
一、填空题
1、进程的属性保存在一个被称为(进程控制块/PCB)的结构体中,这个结构体中包括(进程控制符/PID)、进程组、进程环境、进程的运行状态等。
2、进程在内存中可能会出现不同的状态,通常进程的状态被划分为五种:初始态、(就绪态)、(运行态)、(睡眠/挂起态)和终止态。
【解析】进程在内存中的状态分为5种,包括:初始态、就绪态、运行态、睡眠(挂起)态和终止态。
3、Linux系统中的进程结构类似树形结构,使用(pstree)命令可以查看当前系统中的进程树。进程树的顶端是进程(init),它是系统启动后创建的第一个进程。
【解析】使用pstree命令可以查看当前系统中的进程树;系统启动后创建的第一个进程是init,它处于进程树的顶端,负责启动getty进程、设置运行级别和孤儿进程回收等工作,是所有进程的祖先。
4、调用fork()函数成功创建子进程后,父进程中的fork()函数会返回(子进程的pid),子进程中的fork()函数会返回(0)。
5、若在程序中通过如下所示的循环创建进程,循环结束后,该进程会创建(-1(或31))个子进程。
for(int i=0;i<5;i++)
{
pid=fork();
}
【解析】在每次调用fork()函数创建子进程后,子进程和父进程都会继续执行for循环,如当前i=1,则在i=0时父进程创建出的子进程与父进程本身都会创建一个子进程,如下图所示:
因此i=1时fork()函数调用后进程的数量为
,在下一轮循环中,这4个进程又都会创建一个新进程,进程的数量变为
,由此可得,在第5次循环结束后,进程的数量变为
,则子进程的数量为
-1=31。
二、判断题
1、进程是程序的一次执行过程。(√)
2、exec函数族的功能是:根据指定的文件名或路径,找到可执行文件,用该文件取代调用该函数的进程中的程序,再从该文件的main()函数开始,执行文件的内容。(√)
3、解决僵尸进程的方法是终止其父进程,使其变为孤儿进程。(√)
【解析】通常情况下,解决僵尸进程的方法是终止其父进程。当僵尸进程的父进程被终止后,僵尸进程作为孤儿进程被init接收,init会不断调用wait()函数获取子进程状态,获取已退出的子进程发送的状态信息。孤儿进程永远不会成为僵尸进程。
4、fork()函数执行后,系统会立刻为子进程复制一份父进程的资源。(×)
【解析】Linux系统中的进程机制采用“读时共享,写时复制”的原则,在子进程创建之初并不会复制父进程的全部资源。
5、进程同步机制中的waitpid()函数和wait()函数用于使父进程阻塞等待子进程终止,将子进程进行回收,因此当父进程中调用了这两个函数时,就不会再有僵尸进程产生。(×)
【解析】wait()函数会在有子进程终止时立刻返回,waitpid()函数的一次调用只能回收一个子进程,若因此若子进程数量不唯一时,父进程中调用一次wait()和waitpid(),并不一定能回收所有子进程,也就无法保证所有子进程都被回收,没有僵尸进程产生。
三、单选题
1、在程序中调用fork()函数创建进程,父子进程会获取不同的返回值,下面关于fork()函数的说法,错误的是。(B)
A、若子进程创建成功,父进程的fork()返回子进程pid,子进程的fork()返回0。
B、若子进程创建成功,子进程的fork()返回子进程pid,父进程的fork()返回0。
C、若子进程创建失败,父进程的fork()函数返回-1。
D、若子进程创建成功,子进程将从fork()函数调用处之后的代码开始执行。
【解析】若子进程创建成功,父进程的fork()返回子进程pid,子进程的fork()返回0。
2、下列哪种方法无法查看进程的信息。(C)
A、ps B、top C、kill D、查看/proc目录
【解析】kill命令的功能是通过向进程发送信号控制进程行为。
3、下列哪种方法可以等待接收进程号为pid的子进程的退出状态。(A)
A、waitpid(pid,&status,0)
B、waitpid(pid,&status,WNOHANG)
C、waitpid(-1,&status,0)
D、waitpid(-1,&status,WNOHANG)
【解析】waitpid()函数的第一个参数大于0时,表示回收pid等于该参数的进程,因此排除C、D。若waitpid()函数的第三个参数options为0,waitpid()函数功能与wait()函数功能相同,都阻塞等待子进程的返回状态;若options为WNOHANG,表示子进程若尚未终止,父进程不阻塞等待,立刻返回,因此排除B,选择A。
4、函数waitpid()的返回值等于0时表示的含义是(C)。
A、等待的子进程已终止
B、终止的子进程不唯一
C、使用选项WNOHANG,且没有子进程退出
D、调用异常终止
【解析】若options的值为WNOHANG,但调用waitpid()时发现没有已退出的子进程可收集,则返回0。
5、从后台启动进程,应在命令的添加哪个符号?(A)
A、& B、# C、* D、~
四、简答题
1、简单说明程序和进程的区别。
程序是“死”的,进程是“活”的,程序是指编译好的二进制文件,它存放在磁盘上,不占用系统资源,是具体的;而进程存在于内存中,占用系统资源,是抽象的。当一次程序执行结束之后,进程随之消失,进程所用的资源被系统回收。
2、分析程序,写出程序的执行结果。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
pid_t pid1,pid2;
if ((pid1 = fork()) == 0)
{
sleep(3);
printf("child process_1\n");
exit(0);
printf("child process_1\n");
}
else
{
if ((pid2 = fork()) == 0)
{
sleep(1);
printf("child process_2\n");
return 0;
}
else
{
wait(NULL);
wait(NULL);
printf("info1 from parent process\n");
printf("info2 from parent process\n");
return 0;
}
}
return 0;
}
程序执行结果如下:
child process_2
child process_1
info1 from parent process
info2 from parent process
五、编程题
1、编写程序,在程序中创建一个子进程,使父子进程分别打印不同的内容。
程序实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
else if (pid > 0)
{
printf("This is parent process.\n");
}
else if (pid == 0)
{
printf("This is child process.\n");
}
return 0;
}
编译程序并执行,程序的执行结果如下:
This is parent process.
This is child process.
2、编写程序,在程序中创建一个子进程,使子进程通过exec更改代码段,执行cat命令。
程序实现如下:
exec.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
else if (pid > 0)
{
printf("parent process:pid");
}
else if (pid == 0)
{
printf("child process\n");
execlp("cat", "-b", "exec.c", NULL);
perror("error exec\n");
printf("child process\n");
}
return 0;
}
编译程序并执行,程序的执行结果如下:
parent process:pidchild process
[itheima@localhost itcast]$ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
else if (pid > 0)
{
printf("parent process:pid");
}
else if (pid == 0)
{
printf("child process\n");
execlp("cat","-b","exec.c",NULL);
perror("error exec\n");
printf("child process\n");
}
return 0;
}