Я пытаюсь узнать о потоках и блокировках и написал программу для печати чисел в последовательности, используя два потока, каждый из которых печатает четные и нечетные числа соответственно. Но вроде зашли в тупик. Может кто-нибудь сказать мне, что я делаю не так?

/*
    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;
}
1
themoreyouknow 20 Фев 2016 в 08:25

2 ответа

Лучший ответ

Есть недостаток в том, как вы используете переменные условия. Для вас они сами кажутся каналом для сообщения о том, что что-то нужно делать. Вместо этого используйте их как индикатор, чтобы проверить текущее состояние, нужно ли что-то делать.

Псевдокод:

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 () и сигнализацией события.

Отказ от ответственности: именно так следует использовать условные переменные, но это ни в коем случае не является хорошим программированием для машинного перевода! Убедитесь, что вы прочитали и поняли комментарии к вашему вопросу!

0
Ulrich Eckhardt 20 Фев 2016 в 09:14

Как упоминалось @ user3386109, сигнал, отправленный основной программой, слишком рано (до того, как поток print_odd будет готов к нему) и, следовательно, теряется, что приводит к взаимоблокировке обоих потоков. Скоро отредактирую программу и выложу код.

#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;
}
0
David C. Rankin 20 Фев 2016 в 09:31