写入者使用release内存顺序,读取者使用acquire内存顺序。
memcpy与原子存储/加载调用是否存在重排序的风险?或者加载是否可以互相重排序?这对我来说从未中断过,但也许我很幸运。
#include <iostream>
#include <atomic>
#include <thread>
#include <cstring>
struct envelope {
alignas(64) uint64_t writer_sequence_number = 1;
std::atomic<uint64_t> sequence_number;
char payload[5000];
void start_writing()
{
sequence_number.store(0, std::memory_order::memory_order_release);
}
void publish()
{
sequence_number.store(++writer_sequence_number, std::memory_order::memory_order_release);
}
bool try_copy(char* copy)
{
auto before = sequence_number.load(std::memory_order::memory_order_acquire);
if(!before) {
return false;
}
::memcpy(copy, payload, 5000);
auto after = sequence_number.load(std::memory_order::memory_order_acquire);
return before == after;
}
};
envelope g_envelope;
void reader_thread()
{
char local_copy[5000];
unsigned messages_received = 0;
while(true) {
if(g_envelope.try_copy(local_copy)) {
for(int i = 0; i < 5000; ++i) {
// if there is no tearing we should only see the same letter over and over
if(local_copy[i] != local_copy[0]) {
abort();
}
}
if(messages_received++ % 64 == 0) {
std::cout << "successfully received=" << messages_received << std::endl;
}
}
}
}
void writer_thread()
{
const char alphabet[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
unsigned i = 0;
while(true) {
char to_write = alphabet[i % (sizeof(alphabet)-1)];
g_envelope.start_writing();
::memset(g_envelope.payload, to_write, 5000);
g_envelope.publish();
++i;
}
}
int main(int argc, char** argv)
{
std::thread writer(&writer_thread);
std::thread reader(&reader_thread);
writer.join();
reader.join();
return 0;
}
try_copy
中重新排序这些代码:::memcpy(copy, payload, 5000);
auto after = sequence_number.load(std::memory_order::memory_order_acquire);
我觉得应该使用release
? 同样地,start_writing
看起来应该使用acquire
。 - JesseC={"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}
是一种奇怪的初始化方式。 - curiousguystr = { "..." }
相当奇怪:花括号通常用于结构体或数组,而不是字符串。 - curiousguy