C线程打印数字序列:偶数和奇数打印线程并行运行

时间:2015-04-05 07:37:51

标签: c multithreading

我是多线程编程的新手。我尝试使用偶数和奇数打印线程打印数字序列,并行运行。执行时,代码进入死锁状态。任何人都可以帮我解决这个问题。

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t even, odd;

void printfun1(void *pnt);
void printfun2(void *pnt);

main()
{

    pthread_t pthread1, pthread2;
    int ret1, ret2;
    char *message = "thread 1";
    char *message2 = "thread 2";

    ret1 = pthread_create(&pthread1, NULL, printfun1, (void *)message);

    if(ret1)
    {
        printf("thread creation failed");
    }
    ret2 = pthread_create(&pthread2, NULL, printfun2,(void*) message2);
    if(ret2)
    {
        printf("thread creation failed");
    }

    pthread_join(pthread1, NULL);
    pthread_join(pthread2, NULL);

    exit(0);
}
void printfun1(void *ptr)
{

    char* message = ptr;
    int counter = -1;

    while(counter < 50)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&even, &mutex);
        counter += 2;

        printf("%d \n", counter);
        pthread_cond_signal(&odd);
        pthread_mutex_unlock(&mutex);

        usleep( 1000000);
    }
}

void printfun2(void *ptr)
{

    char* message = ptr;
    int counter2 = 0;
    pthread_cond_signal(&even);
    while(counter2 < 50)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&odd, &mutex);
        counter2 += 2;

        printf("%d \n", counter2);
        pthread_cond_signal(&even);
        pthread_mutex_unlock(&mutex);
        usleep( 1000000);
    }
}

4 个答案:

答案 0 :(得分:1)

该计划至少有一些问题:

  1. 您永远不会初始化条件变量:

    pthread_cond_init(&even, NULL);
    pthread_cond_init(&odd, NULL);
    
  2. 如果在另一个线程没有等待该条件时发出信号,则可以发现死锁。通常,当您使用pthread_cond_wait()时,您还在while循环中检查其他一些共享变量。我重写了你的程序来证明这一点:

    #include <stdio.h>
    #include <pthread.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t  even  = PTHREAD_COND_INITIALIZER;
    pthread_cond_t  odd   = PTHREAD_COND_INITIALIZER;
    
    void *printfun1(void *pnt);
    void *printfun2(void *pnt);
    
    int main(void)
    {
        pthread_t pthread1, pthread2;
        int ret1, ret2;
    
        ret1 = pthread_create(&pthread1, NULL, printfun1, NULL);
    
        if(ret1)
        {
            printf("thread creation failed");
        }
        ret2 = pthread_create(&pthread2, NULL, printfun2, NULL);
        if(ret2)
        {
            printf("thread creation failed");
        }
    
        pthread_join(pthread1, NULL);
        pthread_join(pthread2, NULL);
    }
    
    int counter = 0;
    
    void *printfun1(void *ptr)
    {
        while(counter < 50)
        {
            pthread_mutex_lock(&mutex);
            while ((counter & 1) == 1)
                pthread_cond_wait(&even, &mutex);
    
            printf("%d \n", counter);
            counter++;
            pthread_cond_signal(&odd);
            pthread_mutex_unlock(&mutex);
    
            usleep( 1000000);
        }
        return NULL;
    }
    
    void *printfun2(void *ptr)
    {
        while(counter < 50)
        {
            pthread_mutex_lock(&mutex);
            while ((counter & 1) == 0)
                pthread_cond_wait(&odd, &mutex);
    
            printf("%d \n", counter);
            counter++;
            pthread_cond_signal(&even);
            pthread_mutex_unlock(&mutex);
    
            usleep( 1000000);
        }
        return NULL;
    }
    

    现在您可以看到如何避免死锁。线程只有在知道需要等待条件时才开始等待条件。因此,即使第二个线程在第一个线程没有等待它时发出信号,这也没关系。

答案 1 :(得分:1)

我认为要做好工作,你需要三个互斥锁和三个条件变量。奇数线程必须在程序的整个持续时间内保持奇数互斥锁的锁定。奇数互斥锁解锁的唯一时间是奇数线程在其状态下等待。同样,偶数线程需要在持续时间内保持偶数互斥锁。

并且您需要一个主互斥量和一个主要条件变量,这样奇数和偶数线程可以在锁定各自的互斥锁后发出主信号。

奇数和偶数线后 - 正在运行中 - 锁定了他们的互斥锁
- 并等待他们的条件变量(解锁互斥锁)
然后main可以向奇数线程发出一次信号,以便开始工作。

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

pthread_mutex_t mainMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t oddMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t evenMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mainCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t oddCond = PTHREAD_COND_INITIALIZER;
pthread_cond_t evenCond = PTHREAD_COND_INITIALIZER;

void *printOdd( void *arg )
{
    pthread_mutex_lock( &oddMutex );        // grab the odd mutex

    pthread_mutex_lock( &mainMutex );       // signal main that the odd thread
    pthread_cond_signal( &mainCond );       // is locked and ready for action
    pthread_mutex_unlock( &mainMutex );

    for ( int counter = 1; counter < 50; counter += 2 )
    {
        pthread_cond_wait( &oddCond, &oddMutex );   // wait for the odd signal
        printf( "%d\n", counter );

        pthread_mutex_lock( &evenMutex );   // signal the even thread
        pthread_cond_signal( &evenCond );
        pthread_mutex_unlock( &evenMutex );

        usleep( 100000 );
    }

    pthread_mutex_unlock( &oddMutex );
    return NULL;
}

void *printEven( void *arg )
{
    pthread_mutex_lock( &evenMutex );       // grab the even mutex

    pthread_mutex_lock( &mainMutex );       // signal main that the even thread
    pthread_cond_signal( &mainCond );       // is locked and ready for action
    pthread_mutex_unlock( &mainMutex );

    for ( int counter = 2; counter < 50; counter += 2 )
    {
        pthread_cond_wait( &evenCond, &evenMutex ); // wait for the even signal
        printf( "%d\n", counter );

        pthread_mutex_lock( &oddMutex );    // signal the odd thread
        pthread_cond_signal( &oddCond );
        pthread_mutex_unlock( &oddMutex );

        usleep( 100000 );
    }

    pthread_mutex_unlock( &evenMutex );
    return NULL;
}

int main( void )
{
    pthread_t id1, id2;

    pthread_mutex_lock( &mainMutex );                           // grab the main mutex

    if ( pthread_create( &id1, NULL, printOdd, NULL ) != 0 )    // create the odd thread
        exit( 1 );
    pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the odd thread

    if ( pthread_create( &id2, NULL, printEven, NULL ) != 0 )   // create the even thread
        exit( 1 );
    pthread_cond_wait( &mainCond, &mainMutex ); // wait for the signal from the even thread

    pthread_mutex_unlock( &mainMutex );     // startup has completed, release the main mutex

    pthread_mutex_lock( &oddMutex );        // signal the odd thread to get things rolling
    pthread_cond_signal( &oddCond );
    pthread_mutex_unlock( &oddMutex );

    pthread_join( id1, NULL );              // wait for the threads to finish
    pthread_join( id2, NULL );

    exit( 0 );
}

答案 2 :(得分:0)

首先,条件变量未初始化为&#34; PTHREAD_COND_INTIALIAZER&#34;。来到程序,在第一个线程中,我认为pthread_mutex_unlock应该在pthread_cond_signal之前出现

答案 3 :(得分:0)

以下代码 - 删除不需要的系统函数调用 - 正确处理互斥锁创建/锁定/解锁/销毁 - 从0到49绘制偶数/奇数值 - 正确处理错误记录 - 修改关于未定义函数exit()的编译器警告 - 停止线程在内部while循环中被锁定 - 正确地将顶线程函数定义为&#39; void *&#39;而不是&#39; void&#39; - 将参数设置为pthread_create() - 通过pthread_exit()正确退出线程 - 以及其他一些小修正

#include <stdio.h>
#include <stdlib.h>  // exit(), EXIT_FAILURE
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


void *printfun1(void *);
void *printfun2(void *);

main()
{

    pthread_t pthread1, pthread2;
    int ret1, ret2;

    ret1 = pthread_create(&pthread1, NULL, &printfun1, (void *)message);

    if(ret1)
    {
        perror("thread 1 creation failed");
        exit( EXIT_FAILURE );
    }

    ret2 = pthread_create(&pthread2, NULL, &printfun2,(void*) message2);

    if(ret2)
    {
        perror("thread 2 creation failed");
        exit( EXIT_FAILURE );
    }

    pthread_join(pthread1, NULL);
    pthread_join(pthread2, NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
} // end function: main



int counter = 0;

// Note:
//     1) 0 is even so should be printed
//     2) 50 is beyond the range, so should not be printed
//     3) use do{...}while so program will exit when done, 
//        rather than getting locked in wait loop
void *printfun1(void *ptr)
{
    do
    {
        while( (counter & 1) == 0 )
        {   
            usleep(100);
        }

        pthread_mutex_lock(&mutex);
        printf("%d \n", counter);
        counter++;
        pthread_mutex_unlock(&mutex);

    } while( counter < 50 );
    pthread_exit( 0 );
} // end function: printfun1



void *printfun2(void *ptr)
{
    do
    {
        while( (counter & 1) == 1 )
        { 
            usleep(100);
        }  

        pthread_mutex_lock(&mutex);
        printf("%d \n", counter);
        counter++;
        pthread_mutex_unlock(&mutex);

    } while( counter < 50 );
    pthread_exit( 0 );
} // end function: printfun2