Simulating a train with threads

c, multithreading, pthreads

Solution

The problem with your code is that all `pthread_mutex_lock(&mutex);` does is wait until `mutex` is no longer locked, and then locks it. It doesn't actually check what the value of `t` is.

What you're really looking for is a condition variable:

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void    *train()
{
    int   km;
    static int t = 0;

    km = 1;
    while (km != 30)
    {
        printf("I'm at %02d km\n", km);

        // If we've reached the bridge, wait until less than two trains are on it.
        if (km == 2)
        {
            pthread_mutex_lock(&mutex);
            while (t == 2) { // To be read as: "While two trains are on the bridge, wait."
                pthread_cond_wait(&cond, &mutex);
            }
            ++t; // Put this train onto the bridge.
            pthread_mutex_unlock(&mutex);
        }

        // Leave the bridge.
        if (km == 4)
        {
            pthread_mutex_lock(&mutex);
            --t; // Take this train off the bridge.
            pthread_cond_signal(&cond); // Signal another train to enter.
            pthread_mutex_unlock(&mutex);
        }

        // Move forward 1 km.
        sleep(1);
        ++km;
    }
}

int     main()
{
    pthread_t     train1;
    pthread_t     train2;
    pthread_t     train3;
    pthread_t     train4;

    pthread_create(&train1, NULL, train, NULL);
    pthread_create(&train2, NULL, train, NULL);
    pthread_create(&train3, NULL, train, NULL);
    pthread_create(&train4, NULL, train, NULL);

    pthread_join(train1, NULL);
    pthread_join(train2, NULL);
    pthread_join(train3, NULL);
    pthread_join(train4, NULL);
}

The point of the extra lock and unlock in the `if (km == 4)` bit is to make sure that there aren't multiple threads trying to change/check for the value of `t` at once. (multiple threads accessing the same variable at once usually results in very buggy behaviour!)

Problem

Edit : I think i'm making somthing wrong because when I compile and run my binary twice, I get differents outputs.. I'm trying to understand threads with `pthread` so I did a little code to simulate the passage of a train on a bridge (who can handle only 2 train at a time) I managed to do it for only one train to cross the bridge at a time with a code like this : ``` #include <pthread.h> #include <stdio.h> #include <time.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *train() { int km; static int t = 0; km = 1; while (km != 10) { printf("I'm at %02d km\n", km++); sleep(1); if (km == 2) pthread_mutex_lock(&mutex); if (km == 4) pthread_mutex_unlock(&mutex); } } int main() { pthread_t train1; pthread_t train2; pthread_t train3; pthread_create(&train1, NULL, train, NULL); pthread_create(&train2, NULL, train, NULL); pthread_create(&train3, NULL, train, NULL); pthread_join(train1, NULL); pthread_join(train2, NULL); pthread_join(train3, NULL); } ``` This one worked perfectly (Or maybe did I do something wrong, if so please tell me) And then I tried for the case when 2 train can pass on the bridge at the same time. ``` #include <pthread.h> #include <stdio.h> #include <time.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *train() { int km; static int t = 0; km = 1; while (km != 30) { printf("I'm at %02d km\n", km++); sleep(1); if (km == 2 && t <= 2) { ++t; pthread_mutex_lock(&mutex); } if (km == 4) { t--; pthread_mutex_unlock(&mutex); } } } int main() { pthread_t train1; pthread_t train2; pthread_t train3; pthread_t train4; pthread_create(&train1, NULL, train, NULL); pthread_create(&train2, NULL, train, NULL); pthread_create(&train3, NULL, train, NULL); pthread_create(&train4, NULL, train, NULL); pthread_join(train1, NULL); pthread_join(train2, NULL); pthread_join(train3, NULL); pthread_join(train4, NULL); } ``` So I used a static int to "cap" my train to 2 on the bridge but that don't really work and I don't see why.. My 4 train are strating, then 2 go on the train, the 2 others wait, when the 2 firsts leave the bridge, only one more go on it and the last wait 'till the 3rd one leave the bridge to go.. Actually, I'd like to have the 4 train to go, 2 go on the bridge, 2 waits and when the 2 firsts leave the bridge the 2 other go on the bridge. I'm sorry it's a bit long, but needed for understanding I guess. Thanks for your help !

Original source