【发布时间】:2018-02-12 15:17:15
【问题描述】:
我正在实现一个“序列锁”类,以允许对数据结构进行锁定写入和无锁读取。
将包含数据的结构包含序列值,在写入时序列值将增加两次。写开始前一次,写完后一次。作者在读者之外的其他线程上。
这是保存数据副本的结构,序列值如下所示:
template<typename T>
struct seq_data_t
{
seq_data_t() : seq(0) {};
int seq; <- should this be 'volatile int seq;'?
T data;
};
整个序列锁类在一个循环缓冲区中保存了这个结构的 N 个副本。写入器线程总是覆盖循环缓冲区中最旧的数据副本,然后将其标记为当前副本。写入被互斥锁。
读取功能未锁定。它尝试读取数据的“当前”副本。它在读取之前存储“seq”值。然后它读取数据。然后它再次读取 seq 值,并将其与第一次读取的值进行比较。如果 seq 值没有变化,则认为 read 是好的。
由于写入线程可以在读取发生时更改“seq”的值,我认为应该将 seq 变量标记为 volatile,以便读取函数在读取数据后显式读取该值。
读取函数如下所示:它将在写入者以外的线程上,并且可能在多个线程上。
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.
}
}
问题:
1) seq 在这种情况下必须是 volatile 吗?
2) 在具有多个成员的结构的上下文中,是否只有 volatile 限定变量 volatile,而不是其他成员?也就是说,如果我只在结构中将其标记为 volatile,那么它是否只是 'seq' volatile?
【问题讨论】:
-
volatile完全没有使代码线程安全 - 这是对它应该用于的用途的公然滥用 -
除非您平台的文档中有说明,否则多线程代码中永远不需要
volatile。 -
我不是想用 volatile 使代码线程安全。文字(此处未显示)被锁定。这提供了无锁读取。
-
“由于写入线程可以在读取发生时更改 'seq' 的值,我认为应该将
seq变量标记为 volatile” -这与您上次的评论直接矛盾 -
@ttemple 应该是
std::atomic<int>。
标签: c++ multithreading volatile