从C中的两个线程访问变量

时间:2014-09-02 08:51:17

标签: c multithreading thread-safety

我有以下代码:

int attempts = 0;
while(ptr== NULL && attempts < 60) {
        sleep(1000);
        attempts++;
    }

持续循环等待指针由另一个线程设置。另一个线程就是

ptr = //some value

我的问题是,这样安全吗?这会导致任何内存损坏导致以后难以调试错误情况吗?

P.S:我知道由于缺少volatile关键字,编译器可能会优化ptr。这对我来说无关紧要。我只关心这是否会导致代码的其他无关部分出现问题。

3 个答案:

答案 0 :(得分:3)

这个问题无法回答。 C语言不支持线程。因此,如果您有线程,那么您将获得某些标准或库的支持,这些标准或库必须记录哪些是安全的,哪些不是。最有可能的是,线程标准表示修改一个线程上的对象而另一个线程正在或可能正在访问它是未定义的行为。在那种情况下,它绝对不安全。但是你需要检查你编码的特定标准。

顺便说一句,您无法通过测试来确定它是否安全。它可能看起来很安全,或者似乎在您的测试中做了您期望的事情,然后使用不同的操作系统版本,不同的CPU,不同的编译器选项,不同的BIOS设置或甚至由于运气不好而失败。

答案 1 :(得分:2)

至少,ptr可以声明为volatile;但这已经not了。您确实需要atomic次操作。使用C11,您有<stdatomic.h>标准标头。 最近的海湾合作委员会有atomic builtins你应该使用。你ptr的访问和写作(在#34;你的其他主题&#34;)都应该是原子的!

实际上(不使用原子操作)你会观察到的行为是undefined behavior,并且可能会有很大的变化(使用不同的处理器,不同的编译器等......)。

遗憾的是,在许多x86处理器上,您可能没有注意到UB

您需要编译器通过发出特定的机器指令来强制执行/使用cache coherence

您还可以将condition variables与互斥锁或semaphore一起使用。

如果您的目标处理器支持,则可以考虑使用最新GCC(至少4.9)编译-fsanitize=thread和/或-fsanitize=address(用于调试)。

BTW,您的内存损坏可能完全不相关。您可以考虑使用many platforms支持的valgrind(最好使用-g编译您的程序,如果您愿意,可以尝试使用gcc -O1 -g进行编译。

我还建议使用最近的工具(最近的GCC 4.9版本 - 2014年9月 - 最近的binutils,最近的gdb,最近的libc,最近的内核....)

答案 2 :(得分:0)

据我所知,不。它不安全,可能导致读数不一致。最好的方法是使用互斥锁或二进制信号量保护变量ptr。检查mutex.h中的互斥函数(例如mutex_init,mutex_lock,mutex_unlock等)。