写在前面

又到了 一年一度期末课设的时候,距离考试还有12天的时间,此时胡小宁还没有复习(准确的说是学习)之前的课程,所以在这个平平无奇的周二,胡小宁就要开始做课设了!

实验二 Linux 进程 管理

  1. 实验目的
    通过进程的创建、撤销和运行加深对进程概念和进程并发执行的理解,明确进程和程序之间的区别。

  2. 实验内容和步骤

    (1)进程的创建:

    这里要玩虚拟机了,在虚拟机上玩Centos,也就是基于Linux开发的操作系统。安装什么的就不赘述了,网上都可以找得到对应的教程。如下是安装好之后的界面!

    image-20210622081002064

    肉眼可见的是,Linux操作系统的界面同Windows有很多相似之处。但是捏,我还不太会用Linux,所以下面来简单的介绍一下Linux操作系统的使用吧!

    • Linux编程基础

      1. 熟悉Linux下的c/c++编程环境:vi/gedit编辑器+gcc编译器+gdb调试器

        怎么玩捏?

        • vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本
          编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任
          何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi
          也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。

        请看教程:vi/vim的使用 Linux下的C编程 vim编辑器的使用

      2. 在Linux下新建一个文件夹,命名为hnust_OS。在目录下打开shell。

        新建hnust_OS文件夹

        创建了hnust_OS文件夹。

        敲入命令vim fuckcode.c 就成功的在目录下创建了.c文件。按i,进入编辑模式。代码可以右键复制粘贴过去。然后捏,就可以按ESC退出,再按:进入底线模式,然后输入w保存,q退出。也可直接wq保存并退出!

        底线模式

        一顿操作猛如虎,我们的fuckcode.c便成功了,可以看到下面有了fuckcode.c的文件!

        文件创建成功

        这个时候我们要编译fuckcode了!请看操作!

        • 由于 c 语言是一种高级语言,所以输入完 c 程序后就要对它进行编译。gcc 命令可以用来编译
          c 程序。如果在 gcc 命令后面直接跟上文件名,则编译后的输出结果将存放在标准的 a.out 文件中。
          如果 gcc 命令使用-o 任选项,则可以将编译结果存放在自己命名的文件中。为方便起见,我们使
          用带-o 任选项的 gcc 命令来进行编译。当然,在本次课程设计中也可以使用 gcc 命令进行编译。
          $gcc –o compact compact.c

        编译成功

        可以看到!编译成功!!

        接下来我们./fuckcode来运行。

        效果

        对了,这里要特别声明一下!指导书里写的删除空行的程序试错的!他妈的!把’/n’改成’ ‘,就能实现如上图所示的功能了!

      3. 恭喜,你差不多玩明白了基础操作。下面让我们开始搞课设吧!!!

    先看一下任务要求:

    编写一段程序,使用系统调用 fork()创建一个子进程。当此程序运行时,在系统中有一个父进程和一个子进程活动。让每一个进程在屏幕上分别显示字符:父进程显示字符“b”;子进程显示字符“a”,另外父子进程都显示字符“c”。

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
    #include <stdlib.h>
    main()
    {
    int x;
    srand((unsigned)time(NULL));
    while((x=fork())==-1);
    if (x==0)
    {
    sleep(rand() % 2);
    printf("a");
    }
    else
    {
    sleep(rand() % 3);
    printf("b");
    }
    printf("c");
    }

    可以看到效果如下:

    image-20210622093219176

    分析:fork 建立一个子进程,父进程继续运行,子进程在同样的位置执行同样的程序。对于父进程,
    fork()返回子进程的 pid, 对于子进程,fork()返回 0。出错时返回-1。两个进程同时运行!至于谁先上,这个是哲学问题…

    (2)子进程执行新任务

    任务要求:

    编写一段程序,使用系统调用 fork()创建一个子进程。子进程通过系统调用 exec更换自己原有的执行代码,转去执行 Linux 命令/bin/ls (显示当前目录的列表),然后调用 exit()函数结束。父进程则调用 waitpid()等待子进程结束,并在子进程结束后显示子进程的标识符,然后正常结束。

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
    pid_t pid;
    /* fork a child process */
    pid = fork();
    if (pid < 0)
    { /* error occurred */
    fprintf(stderr, "Fork Failed");
    return 1;
    }
    else if (pid == 0)
    { /* 子进程 */
    execlp("/bin/ls","ls",NULL);
    }
    else { /* 父进程 */
    /* 父进程将一直等待,直到子进程运行完毕*/
    wait(NULL);
    printf("Child Complete");
    }
    return 0;
    }

    效果如下:

    image-20210622094638778

    注意!从指导书复制代码过来的时候,要给头文件加上#include <sys/wait.h>。否则程序无法正常运行哦!

    分析:

    • exec 系列函数用新的进程映象置换当前的进程映象.这些函数的第一个参数是待执行程序的路
      径名(文件名)。这些函数调用成功后不会返回,其进程的正文(text),数据(data)和栈(stack)段被待执行
      程序程序覆盖。但是进程的 PID 和所有打开的文件描述符没有改变,同时悬挂信号被清除,信号重
      置为缺省行为。
    • 使用系统调用 fork()创建一个子进程。子进程通过系统调用 exec更换自己原有的执行代码,转去执行 Linux 命令/bin/ls (显示当前目录的列表),然后调用 exit()函数结束。父进程则调用 waitpid()等待子进程结束,并在子进程结束后显示子进程的标识符,然后正常结束。