有关(非易失性)优化编译器的问题

时间:2020-05-03 11:17:26

标签: c multithreading volatile

我有以下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)) 
        ; 
}

正如我在评论中指出的那样,即使该条目指向的数组可以从另一个线程(甚至实际上直接从内核空间)更改,它也声明为易失性。

以上代码不正确/不安全吗?我的想法是,不能在isready,isready2的主体中执行优化,并且由于我从main内反复执行函数调用,因此每次调用时都应读取适当的内存位置。

另一方面,编译器可以内联这些函数。

是否可能以导致发生单个读取(因此导致无限循环)而不是多个读取(即使这些读取来自加载/存储缓冲区)的方式来做到这一点?

还有第二个问题。是否可以通过仅在某些特定位置强制转换为volatile来防止编译器进行优化?

void func(void)
{
    entry->status = 1;
    while (((volatile struct myentry *) entry)->status != 2)
        ;
}

谢谢。

1 个答案:

答案 0 :(得分:2)

如果内存entry指向的内存可以被另一个线程修改,则该程序具有数据争用,因此行为未定义。即使使用volatile,也是如此。

要让一个变量由多个线程并发访问,在ISO C11中,它必须是atomic type或受到正确同步的保护。

如果使用的是较旧的标准修订版,则标准不提供有关多线程的保证,因此您将受制于编译器的任何特殊行为。

如果使用POSIX线程,则没有可移植的原子操作,但它确实定义了同步原语。

另请参阅:

第二个问题是一个错误,我建议不要这样做,因为不同的编译器可能会以不同的方式解释含义,并且无论哪种方式,行为都仍未正式定义。