2017-02-15 25 views
1

Я пишу программу, которая выполняет гауссово исключение с учетом матрицы A и B. Сначала я собираю делитель и множители, создаю pthreads, которые выполняются в функции gauss, которые выполняют свои операции на одном «столбце». Затем я вызываю main, который генерирует новый делитель и множители и передает обратно для другого раунда операций теми же потоками. Используя условие pthread vars, выполните это.Программа pthreads C зависает при выполнении

Код висит до тех пор, пока я не создаю точку останова, которую он затем продолжит и закончит. Не уверен, что это держит. Может использовать некоторую помощь.

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

//Need one mutex variable and two condition variables (one c var for 
//communicating between threads, and one c var for communicating with main). 
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 
pthread_cond_t condM = PTHREAD_COND_INITIALIZER; 
float arr[3][4] = {{2,-3,1, -22},{7,9,-3, 14},{6,7,2,91}}; 
float mults[3]; 
float divisor; 
int num_items = 3; 

void* gauss(void *mine) 
{ 
    int thread_count=0; 
    int x = *((int *)mine); 

    for(int i=0;i<num_items;i++) 
    { 
     /*do something*/ 
     arr[i][x] = arr[i][x]/divisor; 

     for(int k=0;k<num_items;k++){ 
      if(k!=i) 
       arr[k][x] -= mults[k] * arr[i][x]; 
     } 

     /*lock || wait || signal*/ 
     pthread_mutex_lock(&mut); 
     thread_count++; 
     if(thread_count < num_items) 
      pthread_cond_wait(&cond,&mut); 
     else 
     { 
      pthread_cond_signal(&condM); 
      pthread_cond_wait(&cond,&mut); 
      thread_count = 0; 
     } 
     pthread_mutex_unlock(&mut); 
    } 

    return NULL; 
} 

int main(int argc, const char * argv[]) { 

    int i, j; 
    pthread_t threadr[num_items+1];  /*thread id array */ 
    int is[num_items+1]; 
    printf("Test"); 

// /*input num items*/ 
// printf("input the number of items "); 
// scanf("%d",&num_items); 
//  
// /*input A array*/ 
// printf("input A array\n"); 
// for(i=0;i<num_items;i++) 
//  for(j=0;j<num_items;j++) 
//   scanf("%f",&arr[i][j]); 
//  
// /*input B array*/ 
// printf("input B array\n"); 
// for(i=0;i<num_items;i++) 
//  scanf("%f",&arr[i][num_items]); 

    /*grab first divisor & multipliers*/ 
    divisor = arr[0][0]; 
    for(i=0;i<num_items;i++) 
    { 
     mults[i] = arr[i][0]; 
    } 

    for(i=0;i<num_items+1;i++) 
    { 
     is[i]=i; 
     if(pthread_create(&threadr[i],NULL,gauss,(void *)&is[i]) != 0) 
      perror("Pthread_create fails"); 
    } 

    for(i=1;i<num_items;i++) 
    { 

     pthread_mutex_lock(&mut); 
     pthread_cond_wait(&condM,&mut); 

     divisor = arr[i][i]; 
     for(j=0;j<num_items;j++) 
     { 

      mults[j] = 1; 
      if(j != i) 
       mults[j] = arr[j][i]; 
     } 
     pthread_cond_broadcast(&cond); 
     pthread_mutex_unlock(&mut); 
    } 

    printf("The X values are:\n"); 
    for(i=0;i<num_items; i++) { 
     printf("%0.3f \n", arr[i][num_items]); 
    } 

    /*wait for all threads*/ 
    for(i=0;i<num_items+1; i++) 
     if (pthread_join(threadr[i],NULL) != 0) 
      perror("Pthread_join fails"); 

    return 0; 
} 
+0

Это не объясняет повесить, но заметьте, что небезопасно безоговорочно выбирать элементы главной диагонали как делители. Они могут быть равны нулю (даже для неособых систем) и/или иметь экстремальные значения, которые делают ваш подход численно неустойчивым. –

+0

Правильно, я собирался решить эту проблему. Благодарю за ваш ответ. –

ответ

0

У вас есть состояние гонки (по крайней мере, один), и ваш код не использует его переменные условия правильно. Вы, вероятно, можете исправить первое, зафиксировав последнее. Кроме того, я подозреваю, что вы используете локальную переменную gauss() для общего доступа, но переменные без привязки не используются.

Во-первых, гонки состояние. Рассмотрим основной поток: он запускает три других потока, а затем блокирует мьютексы и ждет, чтобы была указана переменная состояния condM. Но предположим, что нити все успевают сигнализировать condM, прежде чем основной поток начнет ждать? Операции с переменными условий являются незамедлительными - любые сигналы на condM, которые происходят до main(), ждут на нем, будут потеряны.

Теперь давайте переключим передачи, чтобы поговорить о переменных условий. Как the Linux manual for pthread_cond_wait() выразился:

При использовании переменных условия всегда есть логическое сказуемое с участием общих переменных, связанных с каждым условием ждать, что это верно, если нить должна продолжаться. Могут возникнуть побочные пробуждения от функций pthread_cond_timedwait() или pthread_cond_wait(). Поскольку возврат с pthread_cond_timedwait() или pthread_cond_wait() не означает ничего о значении этого предиката, предикат должен быть переоценен при таком возврате.

Другими словами, переменные условия используются для приостановки операций нити, пока данное условие становится истинным. В абстрактных терминах это условие всегда «нормально для этого потока», но это реализовано в контексте конкретных условий. Самое главное, что поток, который просыпается от своего ожидания, никогда по своей сути не сообщает, что условие истинно; это просто указывает, что новоявленная нить должна проверить, является ли условие истинным. Как правило, нить должна также проверяться перед ожиданием в первый раз, так как условие может уже быть правдой.

В псевдокоде, который выглядит следующим образом:

Тема 1:

lock mutex; 
loop 
    if is_ok_to_proceed then exit loop; 
    wait on condition variable; 
end loop 
// ... maybe do mutex-protected work ... 
unlock mutex 

Тема 2:

lock mutex 
    // ... maybe do mutex-protected work ... 
    is_ok_to_proceed = true; 
    signal condition variable; 
unlock mutex 

Вообще говоря, есть также (мьютекс-защищенный) код где-то еще что делает предикат CV ложным, так что иногда потоки действительно выполняют свои ожидания.

Теперь рассмотрим, как это относится к состоянию гонки в main(). Как main() знает, ждать ли на condM()? Там должна быть общая переменная где-то, которая отвечает за нее, и ее ожидание должно быть обусловлено значением этой переменной.Любой поток, который позволяет разрешить основной поток, должен установить соответствующее значение для переменной и сигнал condM. Сама основная нить также должна установить переменную, если необходимо, чтобы указать, что она не готова, в то время, чтобы продолжить.

Конечно, ваше другое использование CV страдает от такой же проблемы.

+0

Благодарим за помощь. Это имело смысл и решило мою проблему. Я лучше понимаю cond_vars. –

 Смежные вопросы

  • Нет связанных вопросов^_^