操作系统折腾记(一)

学习操作系统的精髓在哪里?当然是自己折腾啊!(逃

学习线程的时候,老师在 ppt 中展示了这样一段代码:

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
34
35
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#define NUM_THREADS 5

pthread_t threads[NUM_THREADS];
char **ptr;

void *Hello(void *vargp) {
int myid = *((int*)vargp);
static int cnt = 0;
printf("Hello from No.%d thread, tid=%lu, cnt=%d.\n", myid, threads[myid], ++cnt);
printf("%s\n", ptr[myid]);
pthread_exit(NULL);
return NULL;
}

int main(){
int i;
char *msgs[NUM_THREADS] = {
"Hello from A",
"Hello from B",
"Hello from C",
"Hello from D",
"Hello from E"};
ptr = msgs;
int taskids[NUM_THREADS];
for(i = 0; i < NUM_THREADS; i++){
taskids[i] = i;
pthread_create(threads+i, NULL, Hello, taskids + i);
printf("create No.%d thread, tid=%lu\n", i, threads[i]);
}
pthread_exit(NULL);
}

因为是学习用,所以这段代码有些奇怪的地方,比如在主线程里定义了 msgs 数组,然后拿一个全局指针 ptr 指过去,意思是让我们知道,这个 msgs 在对等线程中不能访问,但是对等线程可以通过全局的 ptr 访问到 msgs——但这些不重要,不是我们折腾的点儿。

老师在 ppt 中贴了 3 次运行的结果,如下图所示:

意思很明确,就是线程的执行顺序是随机的,谁也不知道什么时候当前线程会被切断,转而执行另一个线程。比如,Hello from No.1Hello from B 这两个 printf 之间,就很可能被切断。

然后我无意间发现了一个奇怪的现象。按理说,就算 cnt 自增后被切断了,那切回来输出时,cnt 只会变得更大而不会变小,换句话说,结果的 count 值应该是单调不减的才对,可为什么老师的结果截图中,输出 count=5 之后还会输出 count=3 呢?

和同学们讨论后,我们达成的一致是,cnt 在自增后,会将其值作为参数传递给 printf 的形参,这个过程是不会(或者很小可能)被切断的。随后,即使在执行 printf 过程中线程被切断了、cnt 被其他线程改变了,但是 printf 内的形参值已经不受影响了,于是依旧输出的是原本的 cnt

不过俗话说得好,talk is cheap, show me the code,我们必须要实打实地折腾一番,于是我在虚拟机(Ubuntu 20.04)中编写了上述代码并执行,结果如下:

没错,虽然 cnt 偶尔会被打乱,但运行了很多次,cnt 都遍历完了 1~5 所有的数字,虽然不能说一定,但是可以说大概率下,cnt 自增和传参给 printf 没有被切断。

正面的实验做了,可没有反面的实验总不放心。不是切不断吗,那就人为的切断它呗!切断的方式很简单,在 cnt 自增与传给 printf 之间 sleep 一会儿就行:

1
2
3
4
static int cnt = 0;
++cnt;
sleep(0.1);
printf("Hello from No.%d thread, tid=%lu, cnt=%d.\n", myid, threads[myid], cnt);

运行结果如下:

count 的值单调不减,印证了我们的想法,nice!

但是解决一个旧问题,又出现了一个新问题。从老师的截图中可以看到,count 值和 No 序号神奇地一一对应了,而我们的运行结果并不对应。一个可能的解释是,在老师的机子上,线程被创建和 cnt 自增之间不会被切断,不过……这真的合理吗?


操作系统折腾记(一)
https://xyfjason.github.io/blog-main/2021/09/20/操作系统折腾记(一)/
作者
xyfJASON
发布于
2021年9月20日
许可协议