实验三、观察 Linux 进程/线程的异步并发执行

一、实验目的

通过本实验学习如何创建 Linux 进程及线程,通过实验,观察 Linux 进程及线程的异步执行。理解进程及线程的区别及特性,进一步理解进程是资源分配单位,线程是独立调度单位。

二、实验环境

  • 硬件环境:计算机一台,局域网环境;
  • 软件环境:Linux Ubuntu 操作系统,gcc 编译器;

三、实验内容和步骤

  1. 进程异步并发执行

    1. 编写一个 C 语言程序,该程序首先初始化一个 count 变量为1,然后使用fork函数创建两个子进程,每个子进程对 count 加1后,显示“I am son, count=x”或“I am daughter, count=x”,父进程对 count 加1之后,显示“I am father, count=x”,其中 x 使用 count 值代替。最后父进程使用waitpid等待两个子进程结束之后退出。编译连接后,多次运行该程序,观察屏幕上显示结果的顺序性,直到出现不一样的情况为止,并观察每行打印结果中 count 的值。

      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 "stdio.h"
      #include "unistd.h"
      #include<sys/types.h>
      #include<sys/wait.h>

      int main(){
      pid_t son_pid,dau_pid;
      int count=1;
      son_pid=fork();
      if(son_pid == 0){
      count ++;
      printf("I am son, count = %d\n", count);
      } else {
      dau_pid = fork();
      if(dau_pid == 0){
      count++;
      printf("I am dau, count = %d\n", count);
      }else{
      count++;
      printf("I am father, count = %d\n", count);
      waitpid(son_pid, NULL, 0);
      waitpid(dau_pid, NULL, 0);
      }
      }
      }
    2. 如果我们把上面的程序做如下修改:

      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
      26
      27
      #include "unistd.h"
      #include "stdio.h"
      #include "sys/types.h"
      #include "sys/wait.h"

      int main(){
      pid_t son_pid, dau_pid;
      int count = 1;
      for(int i = 0; i < 2; i++){
      son_pid = fork();
      if(son_pid == 0){
      count++;
      printf("I am son, count = %d\n", count);
      } else {
      dau_pid = fork();
      if(dau_pid == 0){
      count++;
      printf("I am dau, count = %d\n", count);
      }else{
      count++;
      printf("I am father, count = %d\n",count);
      waitpid(son_pid, NULL, 0);
      waitpid(dau_pid, NULL, 0);
      }
      }
      }
      }

      运行以上这个程序,截图给出该程序的运行结果。并给出此结果的原因。

      此程序中使用fork()函数创建了多个子进程,这些子进程异步并发执行,且其使用的资源和地址是独立的,count 在子进程运行过程中不会互相干扰。由于 for 函数循环了两次,第一次循环父进程和子进程中的 count=2,第二次循环父进程和子进程中的 count=3。因为第一次循环中的子进程继承了第二次循环。在第二次循环中创建了更多的子进程,所以第二次循环打印的结果会更多。

  2. 线程异步并发执行
    编写一个 C 语言程序,该程序首先初始化一个 count 变量为1,然后使用pthread_create函数创建两个线程,每个线程对 count 加1后,显示“I am son, count=x”或“I am daughter, count=x”,父进程对 count 加1之后,显示“I am father, count=x”,其中 x 使用 count 值代替。最后父进程使用pthread_join等待两个线程结束之后退出。编译连接后,多次运行该程序,观察屏幕上显示结果的顺序性,直到出现不一样的情况为止,并观察每行打印结果中 count 的值。

    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
    26
    #include "unistd.h"
    #include "stdio.h"
    #include "pthread.h"

    void *daughter(void *num){
    int* a=(int*) num;
    *a += 1;
    printf("I am daughter,cot=%d\n", *a);
    }
    void *son(void *num){
    int* a=(int*)num;
    *a += 1;
    printf ("I am son,count = %d\n", *a);
    }

    int main(){
    pthread_t son_tid, daughter_tid;
    int count = 1;
    pthread_create(&son_tid, NULL, son, &count);
    pthread_create(&daughter_tid, NULL, daughter, &count);
    count ++;
    printf("I am parent,count = %d\n", count);
    pthread_join(son_tid, NULL);
    pthread_join(daughter_tid, NULL);
    return 0;
    }

四、实验总结

观察两个实验结果中 count 值的变化,分析父进程和子进程两者之间的关系以及主线程和子线程之间的关系,写出进程和线程两者之间的区别。

总结:
父进程和子进程是相互独立的,它们运行的资源和地址空间互不干扰。初始继承时,父进程和子进程的 count 都是相同的,但是在之后的count++;中,count 这个变量都是相互独立的,所以我们看到了的实验结果:同一次循环内,所有进程输出的 count 值都是相等的。但是,主线程和子线程的资源和地址空间是共享的。所有的线程共用一个 count ,所以每次输出 count 的值都会+1。最后 count = 4。


实验三、观察 Linux 进程/线程的异步并发执行
https://flowerdown.org/posts/20230525-140705.html
作者
Unrealfeather
发布于
2023年5月25日
许可协议