【问题标题】:Deadlock prevent死锁防止
【发布时间】:2016-04-12 17:55:26
【问题描述】:

需要帮助如何防止我编写的代码出现死锁。或者我需要修复代码以摆脱死锁的任何建议? 同样,当我在 Linux 中运行时,我遇到了分段错误(核心转储)。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#include <semaphore.h>

int cnt;
int *bites;
int *old_bites;
sem_t *sticks;

void *roger(void *arg) {
    int rog = *(int*)arg;

    for(;;) {
        sem_wait(&(sticks[rog]));             // left
        sem_wait(&(sticks[(rog + 1) % cnt])); // right

        bites[rog]++;

        sem_post(&(sticks[(rog + 1) % cnt])); // right
        sem_post(&(sticks[rog]));             // left
}

pthread_exit(NULL);

return NULL;
}

int main(int argc, char *argv[]) {

int i;
pthread_t *rogers;
int *pos;
cnt = (int)strtol(argv[1], NULL, 10);

rogers = (pthread_t *)calloc(cnt, sizeof(pthread_t));
pos = (int *)malloc(cnt * sizeof(int));
bites = (int *)calloc(cnt, sizeof(int));
old_bites = (int *)calloc(cnt, sizeof(int));
sticks = (sem_t *)calloc(cnt, sizeof(sem_t));

for(i = 0; i < cnt; i++) {
    sem_init(&(sticks[i]), 0, 1);
}

for(i = 0; i < cnt; i++) {
    pos[i] = i;
    pthread_create(&(rogers[i]), NULL, roger, (void *)&pos[i]);
}

for(;;) {
    bool dead = true;
    usleep(50000);
    for(i = 0; i < cnt; i++) {
        if(bites[i] != old_bites[i]) {
            dead = false;
        }
    }
    if(dead) {
        exit(EXIT_SUCCESS);
    }

    for(i = 0; i < cnt; i++) {
        printf("%8X", bites[i]);
    }
    printf("\n");
    for(i = 0; i < cnt; i++) {
        old_bites[i] = bites[i];
    }
}

for(i = 0; i < cnt; i++) {
    pthread_join(rogers[i], NULL);  
}

for(i = 0; i < cnt; i++) {
    sem_destroy(&(sticks[i]));
}

exit(EXIT_SUCCESS);
}

【问题讨论】:

  • SegFault 和死锁?也许去记录并添加一个除以零?
  • 好的,我会咬人的。告诉我们到目前为止您为调试应用程序所做的工作。哪一行引发了段错误?
  • OP,你需要做一些调试。 gdbvalgrind 是非常有用的工具,尤其是在涉及分段错误的情况下。更多关于 this question 的信息。另外,@user3386109,我的大脑立即将该链接注册为“bistromath”。
  • @JasonMc92 啊,这解释了标题。 OP 的意思是防止气闸。

标签: c linux deadlock


【解决方案1】:

是的,我希望这会陷入僵局。我不知道cnt 使用的是什么,但我们假设它是 1。在这种情况下,只会创建 1 个线程。该线程将sem_wait(&amp;(sticks[0]));。然后在下一行它将sem_wait(&amp;(sticks[(0+1) % 1 == 0]));。由于信号量的初始值为 1,因此您不能在没有 sem_post 的情况下在同一个信号量上等待两次。因此,该线程将永远等待它无法到达的sem_post,因为它是sem_waiting。

现在考虑cnt &gt; 1 的情况(我们只说cnt == 2 以使其更简单)。这将产生 thread0 和 thread1,并将 0 和 1 作为参数传递给它们的函数。这种情况可能发生:

  • Thread0 执行sem_wait(&amp;(sticks[0]));
  • 上下文切换:thread1执行sem_wait(&amp;(sticks[1]));
  • thread1 执行sem_wait(&amp;(sticks[(1+1) % 2 == 0])); // this blocks because thread0 has already sem_wait'ed this semaphore to 0
  • 上下文切换:thread0执行sem_wait(&amp;(sticks[(0+1) % 2 == 1])); // this blocks because thread1 has already sem_wait'ed this semaphore to 0

现在每个线程都在等待另一个线程的sem_post,然后才能继续 ==> 死锁。我预计这种情况会随着 cnt 值的增加而扩展,尽管会导致死锁的情况会变得更加复杂。

为什么要使用 2 个信号量来保护单个资源?这个理论对我来说是错误的。你用这种方法失去了原子性(如果我明显错了,请纠正我)。

此外,您的 bites 数组存在竞争条件。主线程在读取之前没有观察同步。这可能与段错误有关。

【讨论】:

  • 所以我已经修复了segFault,死锁程序不会结束吗?并连续打印输出?
  • @littlerain 从提供的代码中,我希望您的工作线程最终会死锁。所有的打印都发生在主循环中,它进入一个无限的for循环,如果dead变为真则退出。这有时可能会发生,也可能不会。 pthread_joinsem_destroy 循环永远不会到达。我认为你的信号量数组是一个逻辑错误。你应该只有一个。通过以这种方式使用多个信号量来保护单个资源(bites 数组),您消除了线程同步所基于的原子性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 2011-08-11
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多