3

几周前我在课堂上做了一个练习,我的解决方案很好,但是在长时间观察时我发现了一些奇怪的行为。练习是用两个 posix 线程生成一个死锁,然后解决它。(我对解决方案进行了抽象,因此它没有不必要的代码。

场景如下:

  • 我有两个线程共享两个虚构资源
  • 两个线程按顺序启动,然后尝试占用两个资源(也按顺序)
  • 两个线程有​​不同的占用时间
  • 当一个线程拥有两种资源时,他工作 5 秒,然后释放资源并休息一下,当休息结束时,他再次开始尝试占用这两种资源
  • 每 8 秒,一个函数检查两个线程是否处于等待状态(两个线程都有一个资源并等待第二个)
  • 当发生死锁时,工作更多的线程将被取消然后重新启动

问题来了,取决于机器和编译器标志,输出表明例如线程 A 被取消,但随后线程 B 启动。我在不同的计算机上用不同的编译器和不同的安装进行了尝试。奇怪的是我编译时gcc -Wall -Werror -ansi -pedantic -D_POSIX_C_SOURCE=200809L -pthread -lrt出现了第二个死锁问题,但是当我删除 -Wall 和 -Werror 时,问题出现在 3. deadlock 0o

我在这里上传了源代码。编译标志在源代码中,我尝试了 gcc 和 clang。我还尝试了 Ubuntu 13.04 和 Arch。
是输出,我用“-->”标记了这些行

我是不是忘记了什么,所以出现了这种效果?我认为某些库中没有错误。

4

1 回答 1

1

问题是您将局部变量的地址传递给线程。并且当线程启动时,这个局部变量可能不再存在,并且您正在取消引用曾经保存局部变量但现在保存其他东西的地址位置。

由于它位于程序的堆栈空间中,因此您不会遇到段错误。

以下是代码问题区域的一个亮点以及它是如何引起的:

void resolve_deadlock()
{
    void *pthread_exit_state;
    int id_a = THREAD_A;
    int id_b = THREAD_B;

   <some code to detect deadlocks and kill a thread>

 /* restart the killed thread */
 if (pthread_create(&threads[THREAD_B], NULL, &thread_function, (void *) &id_b) != 0) {
                    perror("Create THREAD_B\n");
                    exit(EXIT_FAILURE);
            }
}

所以程序运行并且:

  1. 调用resolve_deadlock
  2. 线程 X 被杀死
  3. 调用 pthread_create 创建线程
  4. resolve_deadlock 函数结束
  5. 堆栈在下一次函数调用时被覆盖
  6. 操作系统将我们换掉并运行另一个线程
  7. 线程 X 运行并取消引用我们不再存在的本地变量 -> 未定义的行为。
于 2013-08-04T04:31:58.573 回答