-1

我知道旧的 C++ 对线程一无所知,所以这是关于 IRL 编译器的 Q,不是标准的。

我最近正在编写一个代码,其中包含以下内容:

// runs until sun shines or until shutdown is signaled from another thread  
// const is here just to make it clear run is not touching variable 
void run(const bool& shutdown_in_progress) 
{
while(! shutdown_in_progress) //1
{
    //populate data
    for (int i = 0; i< data.size();++i)
    {
         if (shutdown_in_progress) //2
             break; // shutdown latency optimization
         do_slow_stuff_with(data[i]);
    }

}

现在假设我添加了对 shutdown_in_progress 访问的同步(这样该变量就没有竞争条件)。

我是否错误地认为编译器即使使用例如 pthread_mutex_lock/unlock 保护对 bool 的访问也可以进行破坏性优化,将 while(//1) 替换为 if 并完全删除 //2,因为它知道变量必须为 false。或者当变量被同步代码包围时,编译器有办法检测变量的可能突变?

这不是理论上的问题,我正在使用旧的 g++ 编译器开发嵌入式系统。:)

4

1 回答 1

1

正如您自己所说,您在这里超出了 C++ 标准的限制。实际上,有些编译器假设它shutdown_in_progress不会改变,如果他们可以证明while循环内没有任何东西能够改变它。

在您的情况下,shutdown_in_progress是对布尔变量的引用。所以编译器通常不知道该变量是否在其他地方使用另一个名称访问。例如,它可能引用一个全局变量,该变量可能会被do_slow_stuff_with. 如果该函数的源代码在同一个文件中,并且该函数中没有任何布尔变量的赋值,则别名分析可能会启动并告诉编译器没有对任何布尔变量的写访问,所以绝对没有 aliases shutdown_in_progress。但是一旦你在当前翻译单元之外调用了一些函数,旧版本的 gcc 就不能优化访问了。

gcc 可能有第二种方法来证明无法访问所引用的布尔变量,shutdown in_progress即通过跟踪是否存在对创建的真实目标的任何其他引用。例如,如果引用的目标是调用者的局部变量,而调用者从未将该变量的地址传递给任何其他函数,则 gcc 可以确定没有别名,因此该变量无法改变。在你的情况下,我很确定这种优化(如果完成的话)不适用,因为你肯定已经将地址传递shutdown_in_progress给另一个可以启动关闭的函数,或者它是一个全局变量。

最后,gcc 确保不优化对声明为volatile. 虽然 C++ 标准不保证与线程相关的 volatile 变量的任何内容,即使在实践中,如果您尝试在不使用 pthread 原语的情况下通过 volatile 变量进行同步,您可能会得到非常意外的结果,在这种情况下,使用 volatile 变量似乎是安全的。volatiles 的问题在于,它们确保分配给它们中的多个时的写指令是正确排序的,但不能保证读者按该顺序观察写的效果。

最后一点,如果您添加 pthread 函数调用并且拥有邪恶的处理器架构,则执行您编写的函数的一个处理器内核可能会在无限时间使用引用的布尔变量的过时缓存副本。

于 2014-02-07T19:39:50.137 回答