c++ - C++多线程环境下的内存访问

标签 c++ multithreading

我遇到一个问题,主线程中的函数被阻塞,直到在另一个线程中设置局部变量为止。我使用信号量来阻止主线程执行:

int sendRequest(Message request, void *data)
{
semaphore waitForReply;
volatile int result = 0;
volatile int retData[100];
client->sendRequest(request, [&result, &retData](const Message& reply){ // Callback is called from a different thread
   result = reply.result;
   memcpy(retData, reply.retData, sizeof(retData));
   waitForReply.signal();
})
waitForReply.wait();
//At this line we want result var to be updated.
memcpy(data, retData, sizeof(retData));
return result;
}

问题是使用 volatile int result 是否能保证返回结果是从回调中收到的实际值?这是解决这个问题的最佳方法还是使用普通变量和互斥锁更好?

数组 retData 的情况怎么样? (请不要介意数组的大小)

最佳答案

Volatile 在 C 或 C++ 中对于多线程代码没有用处,因为它不会创建内存屏障。但是,您的代码中没有任何内容需要内存屏障,所以您已经没问题了。

坏代码的一个例子是:

// initially
my_pointer = nullptr;
ready_flag = false;

// thread 1
my_pointer = some_pointer_here;
ready_flag = true;

// thread 2
while (!ready_flag) /* wait */;
my_pointer->foo = bar;

这段代码很危险,因为有很多事情可以使对 ready_flag 的写入在对 my_pointer 的写入之前变得可见,即使它在源代码中出现在第二位。在这种情况下,您可以在为 my_pointer 赋值之前对其进行访问。

内存屏障是一条指令,它在内存写入变得可见时强制执行特定的顺序。例如,该代码在写入 my_pointer 和写入 ready_flag 之间需要一个内存屏障。 C++ 标准库提供 std::atomic_thread_fence为了这个目的。此外,std::atomic 类型都可以生成内存屏障。

在您的情况下,您的变量没有相互依赖性(除了整个操作必须完成之外),并且信号量的 wait 方法几乎肯定存在障碍。

实现内核/CPU 之间缓存和内存一致性的确切方法取决于平台。 AFAIK,在 x86 和 ARM 衍生产品上,您根本不需要执行任何操作。在更疯狂的平台上,这通常是由内存栅栏来处理的,无论如何你都会使用它。

关于c++ - C++多线程环境下的内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45204086/

相关文章:

c++ - Visual Studio 2012 上的计算机错误中缺少 GDAL201.dll

c++ - 模板函数应该是静态的吗?

java - 如何使用线程池读取多个文件?

c# - 窗口关闭时的线程回调

java - 在等待 "long"时间时重用 tomcat 线程

ios - NSObjectInaccessibleException',原因 : 'CoreData could not fulfill a fault

c++ - 不使用虚函数的动机

c++ - 从 Visual C++ 调用 Delphi DLL

c++ - 从套接字转换(解析)谷歌 Protocol Buffer 流

python - 如何从 PySpark 中的不同线程在一个 Sparkcontext 中运行多个作业?