【发布时间】:2019-06-02 07:17:11
【问题描述】:
我试图了解线程之间如何共享内存。
我知道每个线程都有自己的堆栈,而堆在每个线程之间共享。每个线程共享公共寻址空间,因此线程内的局部变量可以被另一个线程使用指针看到。这是通过在 Linux 中使用 POSIX 库 pthread 来完成的。
所以,假设它是正确的,如果我创建一个线程并在他的堆栈中分配了一个本地 var,如果包含 var 的堆栈帧被破坏,另一个线程应该读取错误的值。有了这段代码,它就以这种方式工作。
void *_th2(void *args) {
sleep(1);
printf("0x%x\n", *(int *)args);
fflush(stdout);
pthread_exit(NULL);
}
void *_th1(void *args) {
pthread_t tid;
int var = 10;
pthread_create(&tid, NULL, _th2, (void *)&var);
pthread_exit(NULL);
}
但是,如果我使用 malloc 创建 var 以在堆中分配它,它不会显示正确的值。为什么?代码如下
void *_th2(void *args) {
sleep(1);
printf("0x%x\n", *(int *)args);
fflush(stdout);
pthread_exit(NULL);
}
void *_th1(void *args) {
pthread_t tid;
int *var = malloc(sizeof *var);
*var = 10;
pthread_create(&tid, NULL, _th2, (void *)var);
pthread_exit(NULL);
}
【问题讨论】:
-
第一个具有未定义的行为。第二个有内存泄漏,但应该按预期工作。您是如何测试并得出结论的?
-
在第一个代码块中,没有什么会迫使它读取错误的值。第二个线程可能在第一个线程调用
pthread_exit()之前运行。即使它稍后运行,也不会强制立即覆盖无效变量的内存。未定义的行为意味着任何事情都可能发生,包括成功读取旧变量的内存。 -
你应该在
pthread_join()_th1()中的第二个线程pthread_exit()之前。 -
请注意,一般情况下,您不应创建以下划线开头的函数、变量、标记或宏名称。 C11 §7.1.3 Reserved identifiers 的一部分说: — 以下划线开头的所有标识符以及大写字母或另一个下划线始终保留用于任何用途。 — 所有以下划线开头的标识符始终保留保留用作普通和标记名称空间中具有文件范围的标识符。 另见What does double underscore (
__const) mean in C? -
运行第二版代码时看到了什么?你能发布整个程序吗?
标签: c multithreading memory heap-memory stack-memory