1. 实验目的
通过本实验学习如何创建 Linux 进程及线程,通过实验,观察 Linux 进程及线程的异步执行。理解进程及线程的区别及特性,进一步理解进程是资源分配单位,线程是独立调度单位。
2. 实验内容
2.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 26 27
| #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.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.\r\n", count); } else { dau_pid = fork(); if (dau_pid == 0) { count++; printf("I am dau, count = %d.\r\n", count); } else { count++; printf("I am father, count = %d.\r\n", count); waitpid(son_pid, NULL, 0); waitpid(dau_pid, NULL, 0); } } }
|
- 如果我们把上面的程序做如下修改:
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 28 29
| #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.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.\r\n", count); } else { dau_pid = fork(); if (dau_pid == 0) { count++; printf("I am dau, count = %d.\r\n", count); } else { count++; printf("I am father, count = %d.\r\n",count); waitpid(son_pid, NULL, 0); waitpid(dau_pid, NULL, 0); } } } }
|
运行以上这个程序,截图给出该程序的运行结果。并给出此结果的原因。
此程序中使用 fork() 函数创建了多个子进程,这些子进程异步并发执行,且其使用的资源和地址是独立的,count 在子进程运行过程中不会互相干扰。由于 for 函数循环了两次,第一次循环父进程和子进程中的 count=2,第二次循环父进程和子进程中的 count=3。因为第一次循环中创建的子进程会继续执行第二次循环,因此在第二次循环中会创建出更多的子进程,打印的结果也会更多。
2.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 27 28 29 30 31 32 33
| #include <stdio.h> #include <unistd.h> #include <pthread.h>
void* daughter(void *num) { int *a = (int *)num; *a += 1; printf("I am daughter, count=%d.\r\n", *a); }
void* son(void *num) { int *a = (int *)num; *a += 1; printf ("I am son, count=%d.\r\n", *a); }
int main() { pthread_t son_tid, dau_tid; int count = 1;
pthread_create(&son_tid, NULL, son, &count); pthread_create(&dau_tid, NULL, dau, &count);
count++;
printf("I am father, count=%d.\r\n", count); pthread_join(son_tid, NULL); pthread_join(dau_tid, NULL); return 0; }
|
3. 分析与思考
观察两个实验结果中 count 值的变化,分析父进程和子进程两者之间的关系以及主线程和子线程之间的关系,写出进程和线程两者之间的区别。
总结:
父进程和子进程是相互独立的,它们运行的资源和地址空间互不干扰。初始继承时,父进程和子进程的 count 都是相同的,但是在之后的 count++; 中,count 这个变量都是相互独立的,所以我们看到了的实验结果:同一次循环内,所有进程输出的 count 值都是相等的。但是,主线程和子线程的资源和地址空间是共享的。所有的线程共用一个 count,所以每次输出 count 的值都会 +1。最后 count=4。