2015-04-05 3 views
3

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

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

«Я пытался печатать номера последовательно» не что поражение цели использования нескольких потоков? – juanchopanza

+0

@ user2864740, Oh yea .... В отличие от C++, преобразование из 'void *' происходит автоматически в C, правильно? –

+0

@CoolGuy Да. Это одна из тех ... отличий. (См. Stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – user2864740

ответ

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

    Теперь вы можете видеть, как избежать взаимоблокировки. Поток только начинает ждать при условии, когда он знает, что ему нужно ждать при условии. Поэтому, даже если второй поток сигнализировал о состоянии, когда первый поток не ожидал на нем, это не имеет значения.

+0

, вы упомянули, что «нить никогда не дает до мьютекса до тех пор, пока он не будет в состоянии ". Согласно моему пониманию, программа момента вызывает функцию pthread_wait_cond, она помещает вызывающий поток в список потоков, ожидающих условия, и разблокирует мьютекс, это происходит атомарно. Таким образом, этот другой поток может получить этот мьютекс. Я исправлю здесь? –

+0

@ facebook-100001358991487 Да, это правильно. – JS1

+0

@ JS1, Is правильно ли вызывать 'pthread_join', если' pthread_create' терпит неудачу? Будут ли проблемы, когда это будет сделано? –

0

Первое, что переменная условия не инициализируется значением «PTHREAD_COND_INTIALIAZER». Приступая к программе, в первом потоке я думаю, что pthread_mutex_unlock должен появиться до pthread_cond_signal

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); 
} 
+1

Спасибо, было очень полезно. – Kanak

0

следующий код --removes функция ненужная система вызывает --properly обрабатывает создание мьютекса/блокировка/разблокировка/уничтожение --prints четные/нечетные значения от 0 до 49 --properly ручками протоколирование ошибок - исправляет предупреждение компилятора о неопределенной функции exit() - останавливает потоки, заблокированные во внутреннем контуре --properly определяет функции верхнего потока как «void *», а не «void» - правильно задает параметры для pthread_create() --properly выходит из потоков через 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 
Смежные вопросы