c - 我需要内存屏障吗?

标签 c multithreading thread-safety memory-barriers

在下面的 C99 示例中,是否保证在读取或写入缓冲区后设置 buffer_full 标志(即使启用了 -O2 优化)?或者,我是否需要内存屏障来确保正确排序?

我希望它能在对齐的 32 位读写是原子的系统上运行。

假设每个线程只有一个实例正在运行,并且没有其他线程正在访问 bufferbuffer_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() 函数的定义,以及它们自己调用的每个函数,。与 writer_thread()reader_thread() 函数在同一个翻译单元中,但这在某种程度上取决于它们的实现。如果符合标准的编译器不确定优化是否被允许,则它不得执行优化。

由于您的命名暗示这两个函数将在不同的线程中运行,但是,如果没有诸如内存屏障之类的同步操作,您就无法确定一个线程感知 对由不同线程执行的共享、非_Atomic、非volatile 数据的修改。

此外,如果一个线程写入一个非原子变量而另一个线程访问同一个变量(读取或写入),那么就会发生数据竞争,除非同步操作或原子操作以每个可能的整体顺序介入两者之间操作。 volatile 变量在这里并没有真正的帮助(参见 Why is volatile not considered useful in multithreaded C or C++ programming? )。但是,如果您使 buffer_full 成为原子的,或者如果您在其上使用原子读写操作来实现您的函数,那么这将有助于避免不仅涉及该变量而且涉及 buffer< 的数据竞争 以及(对于您当前的代码结构)。

关于c - 我需要内存屏障吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39209420/

相关文章:

windows - Grand Central Dispatch (`libdispatch` ) 能否在 Windows 上可用?

c++ - 公共(public)变量访问的线程安全

c++ - 通知调用者线程已完成

linux - Linux 中的 pthread 概念

c - memset 空指针数组

c - 如何在无符号数组 char 中组合字符和数字

c# - MongoDB C# 驱动程序和线程安全

java - 如果线程处于 TERMINATED 状态,调用 thread.start() 是否安全?

c - 客户端和服务器端的socket编程

在 C 中创建文本中的数字数组