【发布时间】:2020-05-03 11:17:26
【问题描述】:
我有以下 C 代码:
/* the memory entry points to can be changed from another thread but
* it is not declared volatile */
struct myentry *entry;
bool isready(void)
{
return entry->status == 1;
}
bool isready2(int idx)
{
struct myentry *x = entry + idx;
return x->status == 1;
}
int main(void) {
/* busy loop */
while (!isready())
;
while (!isready2(5))
;
}
正如我在评论中所指出的,条目未声明为 volatile,即使它指向的数组可以从另一个线程(或者实际上甚至直接从内核空间)进行更改。
上面的代码不正确/不安全吗?我的想法是无法在 isready、isready2 的主体中执行任何优化,并且由于我在 main 中反复执行函数调用,因此应在每次调用时读取适当的内存位置。
另一方面,编译器可以内联这些函数。是否有可能以导致单次读取(因此导致无限循环)而不是多次读取(即使这些读取来自加载/存储缓冲区)的方式执行此操作?
还有第二个问题。是否可以通过仅在某些地方强制转换为 volatile 来防止编译器进行优化?
void func(void)
{
entry->status = 1;
while (((volatile struct myentry *) entry)->status != 2)
;
}
谢谢。
【问题讨论】:
-
上面的代码不正确/不安全吗?是的,不安全。不能保证对
entry的更新是原子的。如果您在更新过程中阅读entry,则该值可能是无稽之谈。在您假设“无法执行优化”时可能还有很多其他问题。 -
@chux-ReinstateMonica 对。它指向的内存可以改变,而不是指针的值。
-
@AndrewHenle 对状态字段的更新之前有一个内存屏障,因此它是要更新的最后一个字段。并且在状态更改后不再更新条目(直到状态再次更改)。这会改变事情吗?
-
it is not declared volatile--> 为什么不改变struct myentry *entry;-->volatile struct myentry *entry;? -
@chux-ReinstateMonica 我只是想知道它是否真的“正确”。例如。 Linus 在这里 (lwn.net/Articles/233482) 说以下似乎是有道理的: """ 在 C 中,“数据”是易变的,但那是疯狂的。数据不是易变的 - 访问 是易变的。所以说“让这个特定的访问小心”可能是有意义的,但不是“让对这个数据的所有访问都使用一些随机策略”。“”“
标签: c multithreading volatile