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