【问题标题】:Practice program not making deadlock as intended练习程序未按预期产生死锁
【发布时间】:2017-08-15 09:32:19
【问题描述】:

我正在尝试了解我的操作系统课程中的死锁,并且无论我运行多少次,我制作的程序都不会死锁。代码是:

#include <stdio.h>
#include <pthread.h>

int resource1;
int resource2;
void *causeDeadlock1();
void *causeDeadlock2();
void wait(int r);
void signal(int r);
pthread_t tid[2];

int main()
{
    resource1 = 1;
    resource2 = 1;
    pthread_create((&tid[0]), NULL, &causeDeadlock1, NULL);
    pthread_create((&tid[1]), NULL, &causeDeadlock2, NULL);
    return(0);
}

void wait(int r)
{
    while(r<1);
    printf("Done waiting\n");
    r--;
}

void signal(int r)
{
    r++;
}

void* causeDeadlock1()
{
    wait(resource1);
    wait(resource2);

    printf("Thread 1 is running with both resources.\n");

    signal(resource1);
    signal(resource2);

    printf("Thread 1 is done.\n");
}

void *causeDeadlock2()
{
    wait(resource2);
    wait(resource1);

    printf("Thread 2 is running with both resources.\n");

    signal(resource2);
    signal(resource1);

    printf("Thread 2 is done.\n");
}

当我运行它时,我通常看不到输出,但我也正常返回控制台。我认为原因是线程永远不会打印它们拥有资源或它们已经完成,因为它们永远卡在等待函数的 while 循环中。但是,如果是这样的话,程序不应该挂起而不是像什么都没发生一样让我回到控制台吗?

【问题讨论】:

  • 函数:wait()是一个众所周知的系统函数,通常用于延迟到某个子进程退出。通过系统函数名调用函数是一种非常糟糕的编程习惯

标签: c pthreads deadlock


【解决方案1】:

您的程序存在三个问题。 编辑:四,如果你也算上 B. Wolf 的答案。

首先,您的waitsignal 函数不会导致任何数据竞争。它们都不会影响真正的资源 (int r),而是作为参数传递的副本。请记住,C 使用按值调用。你应该解决这个问题,例如

void wait(int *r) {
  while (*r<1);       // still wrong, see below!
  (*r)--;
}

void signal(int *r) {
  (*r)++;
}

... wait(&resource1);
... signal(&resource1);

其次,即使wait如上改变,退出while循环的测试*r &gt;= 1和减量操作也应该原子地执行。否则,有可能两个或多个线程同时获取资源,并且您的 wait 操作的语义存在缺陷。

第三,即使你也修复了第二个问题,你的程序可能死锁,它不是保证死锁的。只有当线程的操作以下列方式交错时才会发生死锁:

  1. causeDeadlock1 获得 resource1
  2. causeDeadlock2 获得resource2
  3. causeDeadlock1 等待 resource2
  4. causeDeadlock2 等待 resource1

重要的是 1 和 2(以任何相对顺序)出现在 3 和 4 之前(同样以任何相对顺序)。

大多数情况下,我希望获得第一个资源的线程也能在另一个线程有机会开始执行之前设法获得第二个资源。因此,如果您只运行一次,我不会打赌死锁。将函数体 causeDeadlock1causeDeadlock2 放入循环中,你肯定会看到死锁(在你修复其他两个问题之后)。

【讨论】:

  • 如何使递减操作原子化?我几乎没有 C 或多线程方面的经验。
  • 您可以使用互斥体(即二进制信号量)或条件变量。 Pthreads 实现了两者。然而,这是一个很长的故事,我建议您在这一点上花一些时间研究并发和同步。
【解决方案2】:

您没有得到任何打印输出的原因是主线程正在退出。您应该在从 main() 返回之前添加它

void *aa;
...
pthread_join(tid[0],&aa);
pthread_join(tid[1],&aa);

return(0);

【讨论】:

    猜你喜欢
    • 2013-12-28
    • 2016-02-15
    • 2012-01-25
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 2020-01-05
    • 2020-07-31
    相关资源
    最近更新 更多