我需要内存屏障吗?
Do I need a memory barrier?
在下面的 C99 示例中,是否保证在读取或写入缓冲区后设置 buffer_full
标志(即使启用了 -O2 优化)?或者,我是否需要内存屏障来确保正确排序?
我希望这在 32 位对齐读写是原子的系统上是 运行。
假设每个线程只有一个实例 运行 并且没有其他线程正在访问 buffer
或 buffer_full
.
char buffer[100];
int buffer_full;
// write interesting data to the buffer. does not read.
void fill_buffer(char* buffer, size_t buffsz);
// read the interesting data in the buffer. does not write.
void use_buffer(const char* buffer, size_t buffsz);
void writer_thread()
{
if (!buffer_full) {
fill_buffer(buffer, sizeof(buffer));
// is a memory barrier needed here?
buffer_full = 1;
}
}
void reader_thread()
{
if (buffer_full) {
use_buffer(buffer, sizeof(buffer));
// is a memory barrier needed here?
buffer_full = 0;
}
}
我将您解释为询问编译器是否可以通过调用 fill_buffer()
和 read_buffer()
重新排序对 buffer_full
的赋值。只有在不改变程序的外部可观察行为的情况下,才允许进行此类优化(以及任何优化)。
在这种情况下,因为buffer_full
有外部链接,编译器不太可能确定是否允许优化。如果 fill_buffer()
和 use_buffer()
函数的定义,以及它们自己调用的每个函数的定义,etc,它可能能够这样做。与 writer_thread()
和 reader_thread()
函数在同一个翻译单元中,但这在某种程度上取决于它们的实现。如果符合标准的编译器不确定优化是否被允许,那么它一定不会执行它。
由于您的命名暗示这两个函数将 运行 在不同的线程中,但是,如果没有内存屏障等同步操作,您无法确定一个线程 运行 的相对顺序 感知 对由不同线程执行的共享、非_Atomic
、非volatile
数据的修改。
此外,如果一个线程写入一个非原子变量而另一个线程访问同一个变量(读取或写入),那么就会发生数据竞争,除非同步操作或原子操作尽可能地介入两者之间整体操作顺序。 volatile
变量在这里并没有真正帮助(参见 Why is volatile not considered useful in multithreaded C or C++ programming?)。但是,如果你使 buffer_full
原子化,或者如果你使用原子读写操作实现你的函数,那么这将有助于避免不仅涉及该变量而且涉及 buffer
的数据竞争(对于您当前的代码结构)。
在下面的 C99 示例中,是否保证在读取或写入缓冲区后设置 buffer_full
标志(即使启用了 -O2 优化)?或者,我是否需要内存屏障来确保正确排序?
我希望这在 32 位对齐读写是原子的系统上是 运行。
假设每个线程只有一个实例 运行 并且没有其他线程正在访问 buffer
或 buffer_full
.
char buffer[100];
int buffer_full;
// write interesting data to the buffer. does not read.
void fill_buffer(char* buffer, size_t buffsz);
// read the interesting data in the buffer. does not write.
void use_buffer(const char* buffer, size_t buffsz);
void writer_thread()
{
if (!buffer_full) {
fill_buffer(buffer, sizeof(buffer));
// is a memory barrier needed here?
buffer_full = 1;
}
}
void reader_thread()
{
if (buffer_full) {
use_buffer(buffer, sizeof(buffer));
// is a memory barrier needed here?
buffer_full = 0;
}
}
我将您解释为询问编译器是否可以通过调用 fill_buffer()
和 read_buffer()
重新排序对 buffer_full
的赋值。只有在不改变程序的外部可观察行为的情况下,才允许进行此类优化(以及任何优化)。
在这种情况下,因为buffer_full
有外部链接,编译器不太可能确定是否允许优化。如果 fill_buffer()
和 use_buffer()
函数的定义,以及它们自己调用的每个函数的定义,etc,它可能能够这样做。与 writer_thread()
和 reader_thread()
函数在同一个翻译单元中,但这在某种程度上取决于它们的实现。如果符合标准的编译器不确定优化是否被允许,那么它一定不会执行它。
由于您的命名暗示这两个函数将 运行 在不同的线程中,但是,如果没有内存屏障等同步操作,您无法确定一个线程 运行 的相对顺序 感知 对由不同线程执行的共享、非_Atomic
、非volatile
数据的修改。
此外,如果一个线程写入一个非原子变量而另一个线程访问同一个变量(读取或写入),那么就会发生数据竞争,除非同步操作或原子操作尽可能地介入两者之间整体操作顺序。 volatile
变量在这里并没有真正帮助(参见 Why is volatile not considered useful in multithreaded C or C++ programming?)。但是,如果你使 buffer_full
原子化,或者如果你使用原子读写操作实现你的函数,那么这将有助于避免不仅涉及该变量而且涉及 buffer
的数据竞争(对于您当前的代码结构)。