如何在这个小型多线程程序中调试死锁

时间:2013-07-19 22:23:45

标签: c++ multithreading pthreads

我是多线程的新手,因此从一个小程序开始。从程序中预期的工作是,通过两个线程一个接一个地打印整数,使得一个线程应该打印一个数字而另一个线程应该打印下一个数字,这个过程应该继续直到定义的最大数量

为此,我写了一个小程序,我面临死锁。我试图使用gdb找到互斥锁所有者,但是当我执行print mutex命令时,我只打印$ 3 = 2。

以下是源代码:

#include <iostream>
#include <fstream>
#include <pthread.h>
#include <signal.h>

const int MAX_NUM = 13;

pthread_cond_t cond[1] = {PTHREAD_COND_INITIALIZER,};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int Count = 0;

using namespace std;

void* thread1(void*)
{
    do {
        cout<<"inside thread 1 abt to acquire lock"<<endl;
        // Increment counter in thread1
        pthread_mutex_lock(&mutex);
        cout<<"inside thread 1 blocked"<<endl;
        pthread_cond_wait(&cond[0],&mutex);
        cout<<"after pthread_cond_wait in thread1"<<endl;
        pthread_cond_signal(&cond[1]);
        if(Count < MAX_NUM)
        {
            Count++;
            pthread_mutex_unlock(&mutex);
            cout<<"Printing from thread 1"<<endl;
            cout<<Count<<endl;
        }
        else
        {
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }
    }while(1);
 }

 void* thread2(void*)
 {
     do{
         cout<<"inside thread 2 abt to acquire lock"<<endl;
         pthread_mutex_lock(&mutex);
         cout<<"inside thread 2 blocked"<<endl;
         pthread_cond_wait(&cond[1],&mutex);
         // Increment counter in thread2
         pthread_cond_signal(&cond[0]);
         if(Count < MAX_NUM)
         {
             Count++;
             pthread_mutex_unlock(&mutex);
             cout<<"Printing from thread 2"<<endl;
             cout<<Count<<endl;
         }
         else
         {
             pthread_mutex_unlock(&mutex);
             pthread_exit(NULL);
         }
    }while(1);
}

int main()
{
    pthread_t t[2];
    void* (*fun[2])(void*);
    fun[0]=thread1;
    fun[1]=thread2;

    for (int i =0 ; i < 2; ++i)
    {
        pthread_create(&t[i],NULL,fun[i],NULL);
    }
    cout<<"threads created"<<endl;

    pthread_cond_signal(&cond[0]);

    cout<<"In main after sending signal"<<endl;


    pthread_join(t[0],NULL);
    pthread_join(t[1],NULL);

    pthread_exit(NULL);
}

输出是:
        内部线程1 abt获取锁定
    内线1阻挡了     内螺纹2 abt获取锁定
    内线2阻挡了     线程创建
    主要发送信号后

我希望main()线程向线程1发送一个信号,它执行它的工作(即更新计数器),然后将信号传递给执行它的工作的线程2(即更新计数器)并将信号传递给线程1.此过程应该继续,直到达到最大数量。如果达到最大数量,则每个进程都会解锁互斥锁并正常退出。

请帮帮我。我真的尝试了很多没用的东西。

2 个答案:

答案 0 :(得分:2)

pthread_cond_t cond[1] = {PTHREAD_COND_INITIALIZER,};

定义一个大小为1的数组,但稍后使用cond[1],即数组中的第二个条目,它是未定义的。你的意思是

pthread_cond_t cond[2] = {PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER};

这看起来像一个不吉利的错字。 (由于前面是MAX_NUM = 13?)

答案 1 :(得分:1)

除了@ TooTone的观察之外,您还需要了解条件变量如何工作的一个方面。如果在没有线程被阻塞的情况下发出条件变量信号,则不会发生任何事情。条件变量没有内存,所以如果稍后一个线程阻塞,它将保持锁定状态,直到再次发出信号为止。

您的main函数在启动线程后立即发出cond[0]信号,因此线程可能尚未到达其阻塞点。或者如果它们被阻止,那么当一个线程向另一个线程发信号通知另一个线程未被阻塞时,可能发生这种情况。因此,在修复条件变量数组后,您将看到测试运行得更多,但最终会再次死锁。

我能够使用快速和快速的方式使其工作在发出条件变量信号之前引入延迟的肮脏技巧。这使线程有时间在信令发生之前到达其阻塞点。这是修改后的代码:

const int MAX_NUM = 13;

pthread_cond_t cond[2] = {PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int Count = 0;

using namespace std;

void* thread1(void*)
{
    do {
        cout<<"inside thread 1 abt to acquire lock"<<endl;
        // Increment counter in thread1
        pthread_mutex_lock(&mutex);
        cout<<"inside thread 1 blocked"<<endl;
        pthread_cond_wait(&cond[0],&mutex);
        cout<<"after pthread_cond_wait in thread1"<<endl;
        if(Count < MAX_NUM)
        {
            Count++;
            pthread_mutex_unlock(&mutex);
            cout<<"Printing from thread 1"<<endl;
            cout<<Count<<endl;
            usleep(1000000);
            pthread_cond_signal(&cond[1]);
        }
        else
        {
            pthread_mutex_unlock(&mutex);
            usleep(1000000);
            pthread_cond_signal(&cond[1]);
            pthread_exit(NULL);
        }
    }while(1);
 }

 void* thread2(void*)
 {
     do{
         cout<<"inside thread 2 abt to acquire lock"<<endl;
         pthread_mutex_lock(&mutex);
         cout<<"inside thread 2 blocked"<<endl;
         pthread_cond_wait(&cond[1],&mutex);
         // Increment counter in thread2
         if(Count < MAX_NUM)
         {
             Count++;
             pthread_mutex_unlock(&mutex);
             cout<<"Printing from thread 2"<<endl;
             cout<<Count<<endl;
             usleep(1000000);
             pthread_cond_signal(&cond[0]);
         }
         else
         {
             pthread_mutex_unlock(&mutex);
             usleep(1000000);
             pthread_cond_signal(&cond[0]);
             pthread_exit(NULL);
         }
    }while(1);
}

int main()
{
    pthread_t t[2];
    void* (*fun[2])(void*);
    fun[0]=thread1;
    fun[1]=thread2;

    for (int i =0 ; i < 2; ++i)
    {
        pthread_create(&t[i],NULL,fun[i],NULL);
    }
    cout<<"threads created"<<endl;
    usleep(1000000);
    pthread_cond_signal(&cond[0]);

    cout<<"In main after sending signal"<<endl;


    pthread_join(t[0],NULL);
    pthread_join(t[1],NULL);

    pthread_exit(NULL);
}

对这类事情使用条件变量不是最好的主意。信号量更适合于任务,因为它们确实有记忆并且记住它们的信号状态,即使没有人在发出信号时等待它们。