【问题标题】:Can't find the deadlock找不到死锁
【发布时间】:2013-06-26 09:21:31
【问题描述】:

我在一次求职面试中遇到了这个问题,我一生都找不到答案(他们不会在最后告诉你答案,因为这是笔试):

int thread2_finished = 0;

void t1() {
    printf("t1 is running\n");
    while (!thread2_finished) { usleep(50); }
    printf("t2 is doing stuff\n");    
}


void t2() {
    printf("t2 is running\n");
    sleep(5);
    printf("t2 woke up\n");    
    thread2_finished = 1;
    printf("t2 finished\n");
}

我们所知道的是它在大多数情况下都有效 - 但有时 thread1 永远不存在(不打印最后一条消息),而 thread2 确实 打印他的所有消息 - 这怎么可能?

我猜我在这里遗漏了一些基本的东西,但我唯一能想到的问题在于缓存 - 比如 T1 加载值 (0) 并缓存它,然后 T2 立即将值更改为1,但出于某种奇怪的原因,T1 将继续使用旧的缓存值,但这对我来说似乎很奇怪。

【问题讨论】:

  • 问题是?
  • 问题是(也已编辑帖子) - thread2 怎么可能在 thread1 处于某种死锁状态时完成?
  • volatile? t1() 可能不知道t2() 已更改thread2_finished 的值这一事实。我相信,如果两个线程在不同的 CPU 内核上运行,这可能会发生。

标签: c synchronization deadlock


【解决方案1】:

这样写的代码看起来是正确的(而且是在逻辑上)但是如果你使用真实的环境它不能正常工作,修复将是 volatile 关键字,但原因是有点复杂,也是因为这个关键字的行为会改变每个语言/编译器,这里是正确的answer

【讨论】:

    【解决方案2】:

    您无法保证 t2 运行时 t1 已经启动。 sleep 不是正确线程同步的有效替代品。

    也有人认为thread2_finished 应该是易变的。实际上,这并不重要,因为编译器不知道 usleep 做了什么,因此不能假设 usleep 不会更改全局变量。另一方面,在许多架构上,您需要更好的同步,而不仅仅是更新全局变量。在某些其他线程上(如果在不同的 cpu 上运行)可能很长时间看不到全局变量的更新值,而在其他线程上(如果不是缓存一致)它可能永远看不到它。操作系统中的锁定原语应提供足够的逻辑,以确保来自一个线程的副作用被其他线程看到。

    简而言之-即使这在大多数情况下都可以,但永远不要这样做。使用适当的锁定、条件变量和信号量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多