小编Dou*_*s B的帖子

为什么我的编译器在 C++ 中使用 -O3 编译时将这个 for 循环“优化”为无限循环

我试图了解什么优化过程会导致以下代码在使用 -O3 优化标志编译时产生无限循环。为了解决这个问题,我知道问题的真正根本原因是这个非空函数中缺少返回,我在嵌入式系统上实现此代码的过程中发生了这种有趣的行为,并且没有但添加了返回值,因为当时我没有使用返回值。

我的问题更多是关于优化过程以及它正在做的事情在其他情况下如何提供帮助/“优化”逻辑是什么样的。

对于更多上下文,我在 ubuntu (c++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0) 中使用 c++ 编译器以及附带的 aarch64-linux-gnu-g++ 编译器时看到了这种行为Xilinx Vitis 2020.2(当然也可以在各自的平台上运行)。

最小可重现示例(我迄今为止创建的):

#include <iostream>

int broken_for_loop(){
    for (int i = 0; i < 10000; i+= 1000){
        std::cout << i << std::endl;
    }
}

int main(int argc, char const *argv[]){
    broken_for_loop();
}
Run Code Online (Sandbox Code Playgroud)

当使用c++ ./broken_loop_test.cpp -o test_local -O3ARM 或同等版本进行编译时。循环的输出是无限的,我已经运行它直到 32b int 结束。如果没有优化,它会按我的预期工作。如果我简单地return 0在 for 循环之后,它也适用于优化。

我天真的怀疑是,因为循环外部没有返回,编译器期望我从循环内部返回或突破,因此删除了测试循环条件的检查/分支,但我想知道我会做什么可以研究一下以获得有关这个特定主题的更多信息(以及一般的优化,自从我上一门编译器设计课程以来已经有一段时间了),而且我对 ASM 不太熟悉,无法自信地识别那里的问题。

任何帮助将不胜感激,谢谢!

因为本节是必需的,所以我会注意到我已经尝试声明volatile i和使用不同类型的整数以及转换常量值并在循环中执行更多/更少操作。没有 return 语句,所有这些都会导致相同的行为。

c++ compiler-errors infinite-loop compiler-optimization undefined-behavior

4
推荐指数
1
解决办法
777
查看次数

是否存在以下情况:解锁然后锁定已解锁的互斥锁是有效的,而另一个线程尝试使用 lock_guard 锁定它?

我为这个糟糕的标题道歉,只是想找人确认我没有疯。

我最近偶然发现了一些已经使用多年而没有人抱怨的代码。我调查它的原因是因为我在大量修改此代码库时遇到此错误:

pthread_mutex_lock.c:90: ___pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
Run Code Online (Sandbox Code Playgroud)

经过一番挖掘,我发现互斥锁的使用(对我来说)非常奇怪。在本质上:

  1. 生成两个线程并与主线程分离(两个线程位于同一个 .cpp 文件中,并共享全局声明的互斥体)
  2. 根据评论,在似乎第一个被击中的线程中,互斥体被解锁,然后在循环中暂停 10us 来锁定,以“允许其他线程处理消息”
  3. 可能会第二次命中的线程(首先生成,但等待接收数据)在 switch 语句中有一个情况,该语句使用 a 锁定互斥体lock_guard

我相信这在很多方面都是未定义的行为,但我收到了一些反对意见,认为应该改变它,因为我正在努力一致且最小化地重现这个确切的错误。

我假设这是为了让互斥体首先被循环线程解锁(从解锁状态,线程还没有要lock_guard处理的数据),然后锁定,并且大部分时间都会被锁定,而lock_guard偶尔会尝试锁定,并且必须等待循环解锁它,此时它可以处理其数据,lock_guard超出范围,并且锁定返回到循环线程。

我认为导致我的错误的是;通过我的修改,线程lock_guard获取数据的速度比预期的要快,因此lock_guard触发了该情况,然后循环线程尝试解锁另一个线程互斥体。

我在寻找:

  • 确认是UB声明互斥量,然后解锁,不加锁
  • 如果循环线程在互斥锁被持有时解锁该互斥锁,则确认它是 UBlock_guard
  • 确认我对导致错误的原因的假设(我基本上已经从参考文献中知道了前两个,但想确保我没有错过一些我不知道的做事的大脑方式)
  • 也许有更好的方法来做到这一点,我认为这可以通过首先将互斥体锁定在循环之外来解决?

我搜索了代码库,互斥体只使用了 4 次,我可以看到:当它被声明时,当它被使用时,当lock_guard它被解锁时,然后被锁定,所以我的 MRE 很短,我认为它基本上有它需要的一切。演示如何使用该互斥锁:

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>

std::mutex data_mtx;

void lg_thread(){
  std::lock_guard<std::mutex> guard(data_mtx);

  usleep(10e6);
}

int main(int argc, char const* argv[]){
  std::thread t1(lg_thread);

  usleep(10000);

  for (int i = 0; i …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading mutex pthreads stdthread

0
推荐指数
1
解决办法
358
查看次数