首页 > 解决方案 > Pthreads而不是共享变量

问题描述

在学习本教程时: https ://www.pluralsight.com/courses/linux-network-programming 我发现了非常有趣的行为,请检查以下代码:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    

void *func(void *arg)
{
    pthread_exit((void *)99);
}

int main()
{    
    pthread_t handle;
    int exitcode;
    int i = 0;
    int y = 5;
    while (1) {
        y++;
        // i++;
        printf("primary thread: y == %d\n", y);
        pthread_create(&handle, NULL, func, "hi!");
        pthread_join(handle, (void **)&exitcode);
        sleep(1);
    }    
}

//gcc -o t failtesting.c -O0  -l pthread  ; ./t
//primary thread: y == 6
//primary thread: y == 1
//primary thread: y == 1
//^C

以某种方式加入子线程会将变量 y 重置为 0,为什么会发生这种情况?

最奇怪的部分是:如果您取消注释 i++,一切都会恢复正常:

gcc -o t failtesting.c -O0  -l pthread  ; ./t 
primary thread: y == 5
primary thread: y == 6
primary thread: y == 7
primary thread: y == 8

标签: cpthreads

解决方案


这 ...

    int exitcode;

[...]

        pthread_join(handle, (void **)&exitcode);

... 产生未定义的行为,因为引用的&exitcode是 a int,但pthread_join会导致将值写入它,就好像它是 a 一样void *

无论任何其他考虑如何,这本身就足以使行为未定义。但是,在考虑为什么void *C 可能将这种情况声明为 UB 时,请考虑 a 的大小大于a 的大小是很常见的int,所以当程序尝试将数据写入 a 时应该发生什么空间太小了?

最奇怪的部分是:如果你取消注释 i++,一切都会恢复正常

诸如此类的异常表明您的程序正在展示 UB。C 标准明确否认对此有任何解释——这是“未定义行为”含义的一部分。

无论如何,看起来你想要这个,而不是:

    void *exit_ptr;
    pthread_join(handle, &exit_ptr);
    exitcode = (int) exit_ptr;

准备好让编译器发出关于指向 int 的指针转换的合理警告,尽管您应该能够通过转换为 来消除它intptr_t


推荐阅读