并行运行线程不可靠的行为

时间:2013-12-15 11:16:23

标签: c linux multithreading pthreads mutex

我写了以下程序。我希望这个功能按顺序打印1,2 程序等待一段时间(例如10秒),然后打印所有结果。

这是代码:

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

我希望每1秒打印1,2,但程序会等待一段时间,然后完全打印所有字符串。谁能告诉我是什么原因?

3 个答案:

答案 0 :(得分:3)

同时访问

int run_now,因此其访问权限需要受到保护。

为此,请使用互斥锁,例如:

...

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

答案 1 :(得分:1)

使用fprintf(stderr,"...")代替printf,或在fflush(stdout)之后添加printf

这是因为stout仅在操作系统决定刷新时才刷新,而stderr在调用fprintf后立即刷新。

答案 2 :(得分:1)

嗯,你的程序有一些问题。首先,printf可以在内部缓冲内容,因此您不会看到它们。这可能就是你所指的。每个fflush后,您需要stdout printf。更严重的问题是您的程序错误,因为它使用非原子非易失性变量进行通信。

thread_function中,编译器可以自由地将run_now的加载移出循环并仅使用寄存器副本,因此循环不会注意到另一个线程更改了记忆中的价值。您应该始终使用原子内在函数来访问这样的共享变量。