尝试使用线程在 C 中按顺序打印数字

Trying to print numbers sequentially in C using threads

我正在尝试学习线程和锁定,并编写了一个程序来使用两个线程按顺序打印数字,每个线程分别打印偶数和奇数。但似乎已经进入了僵局。有人可以告诉我我做错了什么吗?

/*
    threads printing even odd number without shared variable
*/
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  even  = PTHREAD_COND_INITIALIZER;
pthread_cond_t  odd   = PTHREAD_COND_INITIALIZER;

void print_even()
{
    int i = 0;
    do {
        pthread_mutex_lock(&mux);
        pthread_cond_wait(&odd, &mux);
        i+=2;
        printf("%d ", i);
        pthread_cond_signal(&even);
        pthread_mutex_unlock(&mux);
    } while (i<100);
}

void print_odd()
{
    int i = 1;
    do {
        pthread_mutex_lock(&mux);
        pthread_cond_wait(&even, &mux);
        i+=2;
        printf("%d ", i);
        pthread_cond_signal(&odd);
        pthread_mutex_unlock(&mux);
    } while (i<100);
}

int main()
{
    pthread_t podd, peven;
    pthread_mutex_init(&mux, NULL);
    printf("The values are:\n");
    pthread_create(&podd, NULL, (void *)&print_odd, NULL);
    pthread_create(&peven, NULL, (void *)&print_even, NULL);
    pthread_mutex_lock(&mux);
    pthread_cond_signal(&even);
    pthread_mutex_unlock(&mux);
    pthread_join(podd, NULL);
    pthread_join(peven, NULL);
    printf("\ndone\n");
    return 0;
}

如@user3386109 所述,主程序发送的信号太早了(在 print_odd 线程准备好之前),因此丢失,导致两个线程都死锁。将很快编辑程序和 post 代码。

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

pthread_mutex_t even_mux = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t odd_mux = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t main_mux = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t even = PTHREAD_COND_INITIALIZER;
pthread_cond_t odd = PTHREAD_COND_INITIALIZER;
pthread_cond_t ready = PTHREAD_COND_INITIALIZER; /* to signal main that the 
                                                    threads are created */
void print_even ()
{
    pthread_mutex_lock (&even_mux);

    pthread_mutex_lock (&main_mux);
    pthread_cond_signal (&ready);
    pthread_mutex_unlock (&main_mux);

    int i = 0;
    do {
        pthread_cond_wait (&even, &even_mux);
        i += 2;
        printf ("%d ", i);
        pthread_mutex_lock (&odd_mux);
        pthread_cond_signal (&odd);
        pthread_mutex_unlock (&odd_mux);
    } while (i < 100);

    pthread_mutex_unlock (&even_mux);
}

void print_odd ()
{
    pthread_mutex_lock (&odd_mux);

    pthread_mutex_lock (&main_mux);
    pthread_cond_signal (&ready);
    pthread_mutex_unlock (&main_mux);

    int i = 1;
    do {
        pthread_cond_wait (&odd, &odd_mux);
        i += 2;
        printf ("%d ", i);
        pthread_mutex_lock (&even_mux);
        pthread_cond_signal (&even);
        pthread_mutex_unlock (&even_mux);
    } while (i < 100);

    pthread_mutex_unlock (&odd_mux);
}

int main (void)
{
    pthread_t podd, peven;
    pthread_mutex_init (&odd_mux, NULL);
    pthread_mutex_init (&even_mux, NULL);
    pthread_mutex_init (&main_mux, NULL);

    printf ("The values are:\n");

    pthread_mutex_lock (&main_mux);
    if (pthread_create (&podd, NULL, (void *) &print_odd, NULL) != 0) {
        exit (1);
    }
    pthread_cond_wait (&ready, &main_mux);

    if (pthread_create (&peven, NULL, (void *) &print_even, NULL) != 0) {
        exit (1);
    }
    pthread_cond_wait (&ready, &main_mux);

    pthread_mutex_unlock (&main_mux);
    pthread_mutex_lock (&even_mux);
    pthread_cond_signal (&even);
    pthread_mutex_unlock (&even_mux);
    pthread_join (podd, NULL);
    pthread_join (peven, NULL);
    printf ("\ndone\n");

    return 0;
}

您使用条件变量的方式存在缺陷。对你来说,他们本身似乎是一个传达需要做某事的渠道。相反,使用它们作为指标来检查当前状态是否需要做任何事情。

伪代码:

mutex m
condition_var odd
condition_var even
integer i

function handle odd numbers:
   lock(m)
   while true:
      if i is odd:
         print i
         increment i
         signal even
      wait odd

function handle even numbers:
   lock(m)
   while true:
      if i is even:
         print i
         increment i
         signal odd
      wait even

main:
   i = 0
   start thread to handle odd numbers
   start thread to handle even numbers

如您所见,在等待之前,线程会检查共享计数器是奇数还是偶数,然后相应地执行操作。但是,它不需要事件,特别是在 main() 中启动线程和发出事件信号之间没有竞争条件。

免责声明:条件变量应该这样使用,但绝不是好的MT编程!请务必阅读并理解针对您问题的评论!