tte*_*ple 4 c++ multithreading volatile
我正在实现一个'序列锁'类,以允许锁定写入和无锁读取数据结构.
包含数据的结构包含序列值,在写入发生时,该值将递增两次.在写作开始之前,写作完成之后一次.作者在读者之外的其他线程上.
这是包含数据副本的结构,序列值如下所示:
template<typename T>
struct seq_data_t
{
seq_data_t() : seq(0) {};
int seq; <- should this be 'volatile int seq;'?
T data;
};
Run Code Online (Sandbox Code Playgroud)
整个序列锁定类在循环缓冲区中保存此结构的N个副本.编写器线程总是在循环缓冲区中写入最旧的数据副本,然后将其标记为当前副本.写作是互斥锁定的.
读取功能不会锁定.它试图读取数据的"当前"副本.它在读取之前存储'seq'值.然后它读取数据.然后它再次读取seq值,并将其与第一次读取的值进行比较.如果seq值没有改变,则认为读取是好的.
由于写入线程可以在读取发生时更改"seq"的值,因此我认为seq变量应该标记为volatile,以便read函数在读取数据后将显式读取该值.
read函数如下所示:它将在除writer之外的线程上,也许还有几个线程.
void read(std::function<void(T*)>read_function)
{
for (;;)
{
seq_data_type<T>* d = _data.current; // get current copy
int seq1 = d->seq; // store starting seq no
if (seq1 % 2) // if odd, being modified...
continue; // loop back
read_function(&d->data); // call the passed in read function
// passing it our data.
//??????? could this read be optimized out if seq is not volatile?
int seq2 = d->seq; // <-- does this require that seq be volatile?
//???????
if (seq1 == seq2) // if still the same, good.
return; // if not the same, we will stay in this
// loop until this condition is met.
}
}
Run Code Online (Sandbox Code Playgroud)
问题:
1)在这种情况下,seq必须是易变的吗?
2)在具有多个成员的struct的上下文中,只有volatile的合格变量volatile,而不是其他成员?ie,如果我只在结构中标记它是volatile,那么它只是'seq'volatile?
不要使用volatile,使用std::atomic<>.volatile设计用于与内存映射硬件交互,std::atomic<>旨在用于线程同步.使用正确的工具完成工作.
良好std::atomic<>实施的特点:
它们对于标准整数类型是无锁的(long long通常是一切).
它们适用于任何数据类型,但将使用透明互斥锁来处理复杂数据类型.
如果std::atomic<>是无锁的,它会插入正确的内存屏障/栅栏以实现正确的语义.
操作std::atomic<>无法优化,它们毕竟是为线程间通信而设计的.