【问题标题】:C Threads to print sequence of numbers : with even and odd number printing threads running parallelyC线程打印数字序列:偶数和奇数打印线程并行运行
【发布时间】:2015-04-05 07:37:50
【问题描述】:

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

#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);
    }
}

【问题讨论】:

  • “我尝试按顺序打印数字”这不是违背了使用多线程的目的吗?
  • @user2864740 ,哦,是的.... 与 C++ 不同,void* 的转换会在 C 中自动进行,对吧?
  • @CoolGuy 是的。这是其中之一..差异。 (请参阅 stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc)
  • @juanchopanza 抱歉,应该是“尝试打印数字序列”

标签: c multithreading


【解决方案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;
    }
    

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

【讨论】:

  • 您已经提到“每个线程在等待它的条件之前永远不会放弃互斥锁”。根据我的理解,当程序调用 pthread_wait_cond 函数时,它会将调用线程放在等待条件的线程列表中并解锁互斥锁,这是原子发生的。这样其他线程就可以获取该互斥锁。我在这里说得对吗?
  • @JS1 ,如果pthread_create 失败,调用pthread_join 是否正确?这样做会不会有问题?
  • @JS1 非常感谢。那工作得很好。此外,如果两个线程都在不同的处理器中运行,而变量'counter'没有在它们之间共享呢?是否可以让函数只有在收到其他函数的信号后才能运行?
【解决方案2】:

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

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

奇偶线程后
- 已启动并运行
- 已锁定他们的互斥锁
- 并且正在等待他们的条件变量(解锁互斥锁)
然后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 );
}

【讨论】:

  • 谢谢,很有帮助。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    以下代码 --删除不需要的系统函数调用 --正确处理互斥体的创建/锁定/解锁/销毁 --打印从 0 到 49 的偶数/奇数值 --正确处理错误记录 --更正关于未定义函数 exit() 的编译器警告 --停止线程被锁定在内部while循环中 --正确地将顶级线程函数定义为“void*”而不是“void” --正确设置参数到 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      相关资源
      最近更新 更多