0

I'm creating simulation of a train station. Train information is read from a file. Each line of the file represents a train and each train gets its own thread. The main track of the train station can only hold 1 train at a time. Here is my code:

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

The trains input file:

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

The output of the program is:

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

I think my error lies in the train_function. As you can see, train 0 never gets access to the main track. I must be misunderstanding how threads are awoken with condition variables and am getting stuck in a deadlock. What am I missing?

CaddyShack
  • 110
  • 7
  • would [this](http://stackoverflow.com/questions/16522858/understanding-of-pthread-cond-wait-and-pthread-cond-signal) be of any help? As explained there, I thikn you should lock the mutex first, then wait on the condition – Pynchia Jun 17 '15 at 22:31

1 Answers1

3

Yes, you have a slight misunderstanding of pthread_cond_wait. The man page says:

The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. They shall be called with mutex locked by the calling thread or undefined behavior results.

These functions atomically release mutex and cause the calling thread to block on the condition variable cond;

So you need to lock before calling the pthread_cond_wait. That is, your code should be:

/* 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);
kaylum
  • 13,833
  • 2
  • 22
  • 31