Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 内联替换会导致多线程代码中的无限循环吗?_C++_Multithreading_Parallel Processing_Inline - Fatal编程技术网

C++ 内联替换会导致多线程代码中的无限循环吗?

C++ 内联替换会导致多线程代码中的无限循环吗?,c++,multithreading,parallel-processing,inline,C++,Multithreading,Parallel Processing,Inline,请注意:这只是一个出于好奇的问题,而不是编写更好的多线程代码。 当然,我不会也不会在实际项目中编写这样的代码 添加Inline关键字时,可能会发生内联替换。 所以我很好奇 假设我们有这样的代码: static bool done = false; inline void setDone(bool newState) { done = newState; } inline bool getDone() { return done; } void someWorkerThrea

请注意:这只是一个出于好奇的问题,而不是编写更好的多线程代码。 当然,我不会也不会在实际项目中编写这样的代码

添加
Inline
关键字时,可能会发生内联替换。 所以我很好奇

假设我们有这样的代码:

static bool done = false;

inline void setDone(bool newState) {
    done = newState;
}

inline bool getDone() {
    return done;
}

void someWorkerThreadJob() {
    // Accessing without any lock/atomic/volatile
    while (getDone() == false) {
    }
}
someWorkerThreadJob()
可以像下面那样编译并运行到无限循环中吗

void someThreadJob() {
    while (done == false) {
    }
}
这也引出了下一个问题。 那班上的getters和setters呢? 类中定义的成员函数是隐式的
内联的
,因此我认为内联替换可能会发生,因此也会出现同样的问题。
这是否正确?

完成的
的访问必须并行保护,并且在线程之间同步。否则,处理器或编译器可能产生/执行错误的指令序列。您当前的程序格式不正确

您面临的问题是
done
可以缓存在一级CPU缓存中(取决于处理器),或者编译器可以优化对
done
全局变量的访问(通常通过将其放入寄存器,尽管许多编译器实际上并不这样做)

您需要使用原子指令互斥体/锁(或任何同步机制),以便在修改时其他线程可以看到
完成
。对于原子指令,编译器生成适当的内存限制,不将
done
放入寄存器或/或生成同步通信总线的指令(例如在x86_64上)

有关更多信息,您可以查看缓存一致性协议,如and look


在此情况下,主流编译器(如GCC和CLAN)实际上(这里对于C++标准是完全合法的)主要是因为“代码>静态< /代码>和<代码>内联< /COD>关键字帮助编译器。

std::atomic的情况并非如此。在您提供的情况下,内联除了在没有某种锁的情况下访问数据的正常问题之外,没有其他问题。这并不是说将
getDone()
内联到
done
会以某种方式删除
done
的属性,使之成为非静态的或其他东西。就像在示例代码中直接编码
done
一样,存在无限循环的风险,但无论是否内联,这都是正确的,因为cpp的规范将这种对变量的无保护多线程访问视为(我相信)未定义的行为,所以您可能有无限循环,如果不同的线程更新了
done
,您可能会有一个循环最终停止,如果不同的线程更新了
done
,您可能会有一个循环立即停止,就好像它受到了保护一样。奇怪的事情发生在未定义的行为中,因此没有简单的方法来回答您的问题(好吧,我还没有就这一点对C++11规范进行彻底的调查)

正确实现的内联不会改变以不安全的方式执行的内容,因为这是正确内联的某种定义。如果内联一个方法改变了它的行为,使它在多线程环境中停止工作,那么这将是编译器中的一个bug,需要修复


当然,编译器中存在很大的错误空间,这样的错误很可能存在。实际上,内联编译器检测内联可能导致问题的情况,并避免内联或修复问题。在大多数情况下,内联是安全的,不内联的原因是内联代码的模糊性(在发生重载/继承/虚拟调用的情况下)、递归(不能无限地将函数内联到自身中,但可以达到一定的限制)或性能考虑(通常会增加代码大小,但也会导致代码块变得太大,以致其他优化被禁用)。

内联是一条危险的线索。如果有多个线程访问它(以及至少一次写入),则没有任何同步/原子。
,则有未定义的行为(竞争条件)不考虑内联。您可能会误解某些内容何时内联以及为什么内联。关键字
inline
对此不起作用。->编译器可以自由内联每个函数(用于优化目的)虽然这可能不会改变可观察的行为。
inline
关键字提示编译器必须将多次出现的定义(例如标题中的全局变量定义)合并为一个。(在以前的标准中,这样的多个定义违反了ODR原则,通常会导致链接错误。)@Mat是的,正如第一部分所说,这不是我们将要编写的代码。我只是突然对这种情况感到好奇。我认为我的理论是显而易见的,但需要专家的答案。@Scheff如果我没有错的话,你所说的是我们对
inline
关键字的主要期望。但是还有一件事。inline substitution,复制和粘贴发生的地方。内联替换,复制和粘贴发生的地方。正如我已经说过的:编译器可以自行进行内联,并且不受人类作者的控制。这可能不会改变可观察的行为()只要代码不显示。尽管如此,我会考虑并发访问一个未被保护的变量作为未定义的行为…谢谢,但我并不是在问多线程编程。我知道内存障碍之类的东西。如果我没有,我甚至不会认为示例代码首先会进入无限循环。d编译器将如何使用inline关键字处理这种情况。是的,我知道,这是一个无用的问题,但我真的很担心