【操作系统】进程创建实验

Linux创建进程

. 实验目的及实验环境

1.实验目的

           通过观察、分析实验现象,深入理解进程及进程在调度执行和内存空间等方面的特点,理解进程创建和用户缓冲区的使用,掌握在POSIX 规范中fork和kill系统调用的功能和使用。

2.实验环境

   (1)硬件

    • CPU:1核
    • 内存:2G
    • 显示器:Lenovo Display 1920*1080
    • 硬盘空间:50GB

   (2)软件

    • 操作系统名称及版本:CentOS 7.6 64位
    • 使用shiyanlou的Xfce终端

. 实验内容

1、实验前准备工作

        学习man命令的用法,通过它查看fork和kill系统调用的在线帮助,并阅读参考资料,学会fork与kill的用法,复习C 语言的相关内容。

2、实验内容

        根据下发的Linux进程管理实验PPT内容,完成子实验1和将子实验2代码补充完整。并考虑:

 

        先猜想一下这个程序的运行结果。假如运行“./process 20”,输出会是什么样?然后按照注释里的要求把代码补充完整,运行程序。可以多运行一会儿,并在此期间启动、关闭一些其它进程,看process 的输出结果有什么特点,记录下这个结果。开另一个终端窗口,运行“ps aux|grep process”命令,看看process 究竟启动了多少个进程。回到程序执行窗口,按“数字键+回车”尝试杀掉一两个进程,再到另一个窗口看进程状况。按q 退出程序再看进程情况。

3、回答问题

编写、编译、链接、执行实验内容设计中的代码,并回答如下问题:

子实验1:fork面试题

        1.你最初认为运行结果会怎么样?

         我最初认为运行结果应该为输出6个‘-’。

         2.实际的结果什么样?试对产生该现象的原因进行分析。

        实际结果为8个‘-’。我们首先需要知道fork()系统调用的特性,fork()系统调用是Unix下以自身进程创建子进程的系统调用,一次调用,两次返回,如果返回是0,则是子进程,如果返回值>0,则是父进程(返回值是子进程的pid),这是众为周知的。还有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。

       因为printf(“-“);语句有buffer,所以,对于上述程序,printf(“-“);把“-”放到了缓存中,并没有真正的输出,在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。

        3.用户缓冲区如何使用?

         用fflush刷缓存。
         fflush(stdout);

        4.把你的程序源代码附到实验报告后。

        fork面试题原题解析链接https://mp.weixin.qq.com/s/PQmInO2jPnZu0Yv1oze-PA

子实验2:多进程创建及并发执行

        1.你最初认为运行结果会怎么样?

        最开始我觉得应该是num按顺序0~9进行。

        2.实际的结果什么样?有什么特点?试对产生该现象的原因进行分析。

        实际num是随机的,并且每隔SLEEP_INTERVAL秒刷新一次输出在命令行界面。

        特点是每次都输出一定数目的进程,但是,发现每次输出的进程的次序不一样,随机输出。

        每次调用fork(),都会生成一个父进程,一个子进程。把生成父进程返回的子进程pid保存到pid[i]中;把i直接赋给子进程的自编号proc_number,然后调用死循环函数do_something()进行输出。进程是循环创建的,所以进程自编号proc_number是随着i由小变大的,pid也是依次递增的。

        3. proc_number 这个全局变量在各个子进程里的值相同吗?为什么?

        不相同,因为进入子进程,子进程有独立的堆栈,只是复制了一份全局变量。

        4.kill 命令在程序中使用了几次?每次的作用是什么?执行后的现象是什么?

        两次。kill(pid[ch=’0’],SIGTERM);kill(0,SIGTERM);第一个是杀死进程号pid[ch-‘0’],执行后输出的结果中不会再有该进程号。第二次是杀死本组所有进程。即主进程以及它所创建的所有子进程,执行后程序退出结束。

        5.使用kill 命令可以在进程的外部杀死进程。进程怎样能主动退出?这两种退出方式哪种更好一些?

        进程在主函数中用return,或调用exit()都可以主动退出。

        主动退出更好一点,因为使用kill()则是强制性的异常退出

        6.写出fork()和kill()函数原型,并解释函数的功能和参数的含义?

        fork()函数:pid_t fork(void);
        返回值:fork仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
            (1)在父进程中,fork返回新创建子进程的进程ID;
            (2)在子进程中,fork返回0;
            (3)如果出现错误,fork返回一个负值;
        在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

        kill()函数:int kill(pid_t pid, int sig);
        函数参数:①pid:指定进程的进程ID,注意用户的权限,比如普通用户不可以杀死1号进程(init)。
            pid>0:发送信号给指定进程
            pid=0:发送信号给与调用kill函数进程属于同一进程组的所有进程
            pid<0:发送信号给pid绝对值对应的进程组
            pid=-1:发送给进程有权限发送的系统中的所有进程

        7.ps aux|grep process命令功能是什么?并解释结果的含义。

        如果直接用ps命令,会显示所有进程的状态,通常结合grep命令查看某进

程的状态。

  • 方案设计

 

  • 测试数据及运行结果
  •  

 

 

五.总结

  1. 实验过程中遇到的问题及解决办法;

        问题:运行程序得不到结果。

        解决方法:一定要在修改完fork.c文件后在终端输入gcc fork.c -o fork重新编译该文件!完成后在终端输入./fork即可。

        问题:遇到代码输入错误,导致结果输入不出来

        解决办法:根据提示错误信息,返回代码界面,进一步修改测试

        问题:遇到不理解的细节以及结果

        解决办法:及时上网查询资料

  1. 对设计及调试过程的心得体会。

        设计代码一定要足够完善,理清思路,要有逻辑地设计代码,清楚每一部分的功能以及作用,调试代码的过程中一定要细心,边改边测试。

六.附录:源代码(电子版)

子实验1:

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

        int i;

        for (i = 0; i < 2; ++i)

        {

                fork();

                printf("-");

        }

        wait(NULL);

        wait(NULL);

        return 0;

}

子实验2:

#include <stdio.h> 
#include <unistd.h> 
#include <signal.h>
#include <ctype.h> 
#include <sys/types.h>
#include <stdlib.h>
#define MAX_CHILD_NUMBER 10 
#define SLEEP_INTERVAL 2 
int proc_number = 0; 
void do_something();
int main(int argc, char* argv[])
{
int child_proc_number = MAX_CHILD_NUMBER;
int i, ch;
pid_t  child_pid;
pid_t pid[10] = { 0 }; 
if (argc > 1) 
{
child_proc_number = atoi(argv[1]);
child_proc_number = (child_proc_number > 10) ? 10 :
child_proc_number;
}
for (i = 0; i < child_proc_number; i++) 

{
child_pid = fork();
if (child_pid == 0) 

{
proc_number = i;
do_something();
}
else if (child_pid > 0) 

{
pid[i] = child_pid;
}
}
while ((ch = getchar()) != 'q') 

{
if (isdigit(ch)) 

{
kill(pid[ch - '0'], SIGTERM);
}
}
kill(0, SIGTERM);
return 0;
}
void do_something() 

{
for (;;) 

{
printf("-> %d -> %d\n", proc_number, getpid());
sleep(SLEEP_INTERVAL);
}
}

  • 6
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值