muradin
muradin

Reputation: 1277

parallel running of threads unreliable behaviour

I've wrote the following program. I expect that this function print 1, 2 sequentially but the program waits some time(for example 10 sec) and then prints all of the result.

here is the code:

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

void *thread_function(void *arg);
char message[] = "Hello World";

int run_now = 1;

int main() 
{
    int res;

    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) 
    {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }

    int print_count1 = 0;
    while(print_count1++ < 20) 
    {
        if (run_now == 1) 
        {
            printf("1");
            run_now = 2;
        }
        else 
        {
            sleep(1);
        }
    }

    printf("\nWaiting for thread to finish...\n");

    res = pthread_join(a_thread, &thread_result);
    if (res != 0) 
    {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined. \n");    
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) 
{
    int print_count2 = 0;
    while(print_count2++ < 20) 
    {
        if (run_now == 2) 
        {
            printf("2");
            run_now = 1;
        }
        else 
        {
            sleep(1);
        }
    }
}

i expect to 1, 2 be printed every 1 seconds, but program is waiting some times and then prints all of the string entirely. can anybody tell me what's the reason?

Upvotes: 0

Views: 110

Answers (3)

alk
alk

Reputation: 70931

int run_now is accessed concurrently and therefore its access needs to be protected.

To do so use a mutex for example:

...

int run_now = 1;
pthtread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int main() 
{
    ...

    while(print_count1++ < 20) 
    {
        pthread_mutex_lock(&mutex);
        int run_now_equals_1 = (run_now == 1);
        if (run_now_equals_1)
        {
            printf("1");
            run_now = 2;
        }
        pthread_mutex_unlock(&mutex);

        if (!run_now_equals_1)
        {
            sleep(1);
        }
    }

    ...
}

void *thread_function(void *arg) 
{
    int print_count2 = 0;

    while(print_count2++ < 20) 
    {
        pthread_mutex_lock(&mutex);
        int run_now_equals_2 = (run_now == 2);
        if (run_now_equals_2) 
        {
            printf("2");
            run_now = 1;
        }
        pthread_mutex_unlock(&mutex);

        if (!run_now_equals_2)
        {
            sleep(1);
        }
    }
}

Upvotes: 3

mornfall
mornfall

Reputation: 428

Well, there are a few problems with your program. First, printf may buffer things internally, so you won't see them. This is probably what you refer to. You need to fflush stdout after each printf. The more serious problem is that your program is wrong, as it uses a non-atomic, non-volatile variable for communication.

In your thread_function, the compiler is free to move the load of run_now out of the loop and only work with a register copy, hence the loop won't ever notice that another thread changed the value in memory. You should always use atomic intrinsics to access shared variables like this.

Upvotes: 1

HAL9000
HAL9000

Reputation: 3751

Use fprintf(stderr,"...") instead of printf, or add a fflush(stdout) after each printf.

This is because stout is flushed only when OS decides to flush it, while stderr is flushed as soon as fprintf is called.

Upvotes: 1

Related Questions