2010-06-19 278 views
4

在C中我有一个指针,声明为volatile并初始化为null。一个线程读取和另一个写入volatile变量 - 线程安全?

void* volatile pvoid; 

线程1偶尔会读取指针值来检查它是否为非null。线程1不会设置指针的值。 线程2将只设置一次指针的值。

我相信我可以脱身而不使用互斥或​​条件变量。
是否有任何原因线程1会读取损坏的值或线程2会写入损坏的值?

回答

2

如果该值适合单个寄存器(如内存对齐的指针),这是安全的。在其他情况下,可能需要多条指令读取或写入该值,读取线程可能会损坏数据。如果您不确定读取和写入操作在所有使用情况下都会采用单个指令,请使用原子读取和写入操作。

+0

好的,所以在某些平台上有可能无法很好地处理指针地址。但是你的回答表明,检查一个布尔标志是否从0变为非零是可以的,因为即使读取值被破坏,它仍然可能返回非零值,并且只有在写入发生之后。如果损坏的值恰好为零,那么检查线程会在下一次读取时获取它。是吗? – 2010-06-19 18:30:48

+0

由于读取中断了写入,并且一个或另一个会占用多于一条指令,所以会发生损坏。如果你的标志是单个字节,那么我不能想到它可能被中断的情况,但是不能保证标志和指针被串行写入。如果你有原子操作,它们比标志更好。 – drawnonward 2010-06-19 18:53:56

-2

在大多数平台上,指针值可以在单个指令中读取/写入,可以设置,也可以不设置。它不能在中间中断,并且包含损坏的值。在这种平台上不需要互斥锁。

+3

在所有平台上都不是这样 – jdehaan 2010-06-19 18:12:56

+0

这不适用于哪种平台? 16位整数的CPU? – progrmr 2010-06-19 18:22:13

+0

具有非32位存储器访问的系统,确实存在,特别是在DSP-land中。此外,必须对齐32位内存访问,并且访问的值未对齐。 – 2010-06-19 18:46:58

0

不幸的是,你不能可移植性做出什么纯C.

GCC是原子的任何假设,但确实提供了一些原子的内置函数,需要使用你许多架构的正确指令的照顾。有关更多信息,请参阅Chapter 5.47 of the GCC manual

0

好吧,这看起来很好..唯一的问题将发生在这种情况下 让线程A是你的检查线程和B修改一个.. 事情是检查的平等不是原子在技术上首先值应该是复制到寄存器然后检查然后恢复。让我们假设线程A已经复制到寄存器,现在B决定改变这个值,现在你的变量的值改变了。所以当控制回到A时,即使它根据线程被调用的时间,它也会说它不是null。这似乎在这个程序无害,但可能会导致问题..

使用互斥体..简单enuf ..和u可以肯定你没有同步错误!

+0

无论您是否将其加载到寄存器中,您都会遇到它在您查看后可能会更改的情况。 – progrmr 2010-06-19 18:23:48

3

为了使线程安全,您必须对变量进行原子读取/写入操作,它在所有时序情况下都是不稳定的。在Win32下有互锁函数,在Linux下,如果你不想使用重量级互斥体和条件变量,你可以使用build it yourself with assembly

如果您不是针对GPL,那么http://www.threadingbuildingblocks.org及其atomic<>模板看起来很有前途。 lib是跨平台的。

+1

我有点困惑。变量是多么易变,确保它首先是线程安全的? – Laz 2010-06-19 18:20:44

+0

挥发性涉及的内存屏障对于原子机制起作用是必不可少的,但只是整体的一部分。 – jdehaan 2010-06-19 18:25:08

0

取决于您的编译器,体系结构和操作系统。 POSIX(因为这个问题被标记为pthreads我假设我们不是在谈论Windows或其他线程模型),并且C没有给出足够的约束来解决这个问题。

安全的假设当然是保护与互斥体访问指针。然而根据你对问题的描述,我想知道pthread_once是不是一个更好的方法。当然,在问题中没有足够的信息来表达某种方式。

相关问题