当只有一个线程写入共享变量时,是否需要锁定?

我有2个线程和一个共享的float全局。 一个线程只写入变量,而另一个线程只读取它,我是否需要锁定对此变量的访问? 换一种说法:

 volatile float x; void reader_thread() { while (1) { // Grab mutex here? float local_x = x; // Release mutex? do_stuff_with_value(local_x); } } void writer_thread() { while (1) { float local_x = get_new_value_from_somewhere(); // Grab mutex here? x = local_x; // Release mutex? } } 

我主要担心的是float的加载或存储不是primefaces的,因此local_x中的reader_thread最终会出现虚假,部分更新的值。

  1. 这是一个有效的问题吗?
  2. 是否有另一种方法可以在没有互斥锁的情况下保证primefaces性?
  3. 使用sig_atomic_t作为共享变量是否可行,假设它有足够的位用于我的目的?

有问题的语言是使用pthreads的C.

不同的体系结构具有不同的规则,但通常,对齐的int -sized对象的内存加载和存储是primefaces的。 更小和更大可能是有问题的。 因此,如果sizeof(float) == sizeof(int)你可能是安全的,但我仍然不会在便携式程序中依赖它。

此外, volatile的行为并没有特别明确定义……规范使用它来防止优化对内存映射设备I / O的访问,但没有说明它在任何其他内存访问上的行为。

简而言之,即使在float x上加载和存储是primefaces的,我也会使用显式内存屏障(尽管平台和编译器有多大差异),而不是依赖于volatile 。 如果没有加载和存储是primefaces的保证,你将不得不使用锁,这意味着内存障碍。

根据GNU C库文档的第24.4.7.2节:

实际上,您可以假设int和其他不超过int整数类型都是primefaces的。 您还可以假设指针类型是primefaces的; 这很方便。 这两个假设都适用于GNU C库支持的所有机器以及我们所知道的所有POSIX系统。

float技术上不计入这些规则,尽管如果float与你的体系结构中的int大小相同,你可以做的是使你的全局变量为int ,然后每次你将它转换为带有union的float读或写它。

最安全的做法是使用某种forms的互斥锁来保护对共享变量的访问。 由于关键部分非常小(读/写一个变量),你几乎肯定会从轻量级互斥锁(如自旋锁)中获得更好的性能,而不是重量级的互斥体,这使得系统成为可能要求做好自己的工作。

我会锁定它。 我不确定您的环境中有多大float ,但它可能无法在一条指令中读/写,因此您的读者可能会读取一半的写入值。 请记住, volatile并没有说明操作的primefaces性,它只是声明读取将来自内存而不是缓存在寄存器或类似的东西中。

赋值不是primefaces的,至少对于某些编译器而言,并且在某种意义上它需要执行单个指令。 下面的代码由Visual C ++ 6.0生成 – f1和f2的类型为float。

 4: f2 = f1; 00401036 mov eax,dword ptr [ebp-4] 00401039 mov dword ptr [ebp-8],eax 

我相信你应该使用互斥锁。 有一天,您的代码可能在没有实际浮点硬件的系统上运行,而是使用仿真,从而产生非primefaces浮点变量。 举个例子,请看这里的 -msoft-float。

我的回答并不是很有用。 gcc -msoft-float可能只是gcc -msoft-float加载和存储不是primefaces的特定情况。

因为它只是内存中的一个单词,所以你只需要挥发性声明即可。

我不认为你保证你在阅读它时会有最新的价值,除非你使用锁。

很可能,没有。 由于你没有机会进行写冲突,唯一的问题是你是否可以在半写时阅读它。 你的代码很可能不会在一个平台上运行,如果你用线程写一些东西,在一个单独的操作中不会发生浮点运算。

但是这是可能的,因为C中float的定义并不要求底层硬件存储限于处理器的字大小。 您可能正在编译机器代码,例如,符号和尾数是用两种不同的操作编写的。

我认为,真正的问题是两个问题:“在这里使用互斥体有什么缺点?” 并且“如果我读取垃圾会有什么影响?”

也许你应该编写一个断言而不是互斥锁来确定浮点数的存储大小是小于还是等于底层CPU的字大小。