2015-06-17 4 views
0

Я создаю симуляцию железнодорожного вокзала. Информация о поезде считывается из файла. Каждая строка файла представляет собой поезд, и каждый поезд получает свою собственную нить. Главный след железнодорожного вокзала может содержать только 1 поезд за раз. Вот мой код:Поделиться переменной между несколькими потоками

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <string.h> 
#include <readline/readline.h> 
#include <unistd.h> 

pthread_mutex_t main_track_mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t main_track_condition_var = PTHREAD_COND_INITIALIZER; 
int main_track_status = 0; 

void *train_function(void *args) { 
    /* Parse train information */ 
    int line_number = atoi(strtok(args, ":,")); 
    char *priority_direction = strtok(NULL,":,"); 
    int loading_time = atoi(strtok(NULL, ":,")); 
    int crossing_time = atoi(strtok(NULL, ":,")); 

    /* Load train */ 
    sleep(loading_time/10); 
    printf("Train %d is ready to go %s\n",line_number,priority_direction); 

    /* If the main track is currently in use, wait for it to become available */ 
    while(main_track_status) 
     pthread_cond_wait(&main_track_condition_var, &main_track_mutex); 

    /* Use the main track */ 
    pthread_mutex_lock(&main_track_mutex); 
    main_track_status = 1; 
    printf("Train %d is ON the main track going %s\n",line_number,priority_direction); 
    sleep(crossing_time/10); 
    main_track_status = 0; 

    /* Notify other trains main track is empty */ 
    pthread_mutex_unlock(&main_track_mutex); 
    pthread_cond_signal(&main_track_condition_var); 
    printf("Train %d is OFF the main track after going %s\n",line_number,priority_direction); 

    pthread_exit(0); 
} 

int main() { 
    FILE *ptr_file; 
    char buff[10]; 
    int train_count = 0; 
    char *train; 
    char line[15]; 
    pthread_t trains[3]; 

    ptr_file = fopen("./trains.txt", "r"); 

    if (!ptr_file) 
    { 
     perror("fopen for trains.txt failed"); 
     exit(EXIT_FAILURE); 
    } 

    /* Create train for each line of file */ 
    while (fgets(buff,10, ptr_file)!=NULL) { 
     train = (char*)malloc(10 * sizeof(char)); 

     /* Include line number from file in train information */ 
     sprintf(line, "%d:", train_count); 
     strcat(line, buff); 
     strcpy(train, line); 

     if(pthread_create(&trains[train_count], NULL, &train_function, (void *) train)) 
     { 
      perror("pthread create failed"); 
      exit(EXIT_FAILURE); 
     } 
     train_count++; 
    } 
    fclose(ptr_file); 

    /* Wait for all trains to leave the station */ 
    for (int x = 0; x < train_count; x++) { 
     pthread_join(trains[x], NULL); 
    } 

    free(train); 
    exit(EXIT_SUCCESS); 
} 

поездам входного файла:

e:10,6 
W:5,7 
E:3,10 

Выход программы:

Train 1 is ready to go W 
Train 1 is ON the main track going W 
Train 1 is OFF the main track after going W 
Train 2 is ready to go E 
Train 2 is ON the main track going E 
Train 0 is ready to go e 
Train 2 is OFF the main track after going E 

Я думаю, что моя ошибка заключается в train_function. Как вы можете видеть, поезд 0 никогда не получает доступ к основному треку. Должно быть, я неправильно понимаю, как потоки пробуждаются с переменными состояния, и я застреваю в тупике. Что мне не хватает?

+0

бы [это] (http://stackoverflow.com/questions/16522858/understanding-of-pthread-cond-wait-and-pthread-cond-signal) быть любой помощи? Как объяснялось там, я должен сначала заблокировать мьютексы, а затем ждать по состоянию – Pynchia

ответ

3

Да, у вас есть небольшое недоразумение pthread_cond_wait. man page говорит:

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

Эти функции атомарно высвобождают мьютексы и вызывают вызывающий поток для блокировки переменной условия cond;

Так что вам нужно заблокировать перед вызовом pthread_cond_wait. То есть, ваш код должен быть:

/* If the main track is currently in use, wait for it to become available */ 
pthread_mutex_lock(&main_track_mutex); /* SHOULD LOCK HERE */ 
while(main_track_status) 
    pthread_cond_wait(&main_track_condition_var, &main_track_mutex); 

/* Use the main track */ 
//pthread_mutex_lock(&main_track_mutex); /* INCORRECT */ 
//<..SNIP..> 
pthread_mutex_unlock(&main_track_mutex); 
pthread_cond_signal(&main_track_condition_var); 
+0

. Я обязательно прочитаю страницы руководства более тщательно. Спасибо. – CaddyShack

+0

Вам лучше всего запросить сигнал изнутри критического раздела, то есть ** перед ** разблокировкой мьютекса. – alk

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