(C,pthreads)让多个线程同步并继续在一起

时间:2017-06-17 20:36:40

标签: c multithreading synchronization pthreads

我有一个由多个线程组成的程序。 这些线程必须在某个时刻同步,继续一起,完成不同长度的工作,然后再次同步。

以下是我的意思的例子:

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

#define NUM_THREADS 10

void* thread(void* idp);

int threads_running = 0;
pthread_mutex_t* mutex;
pthread_cond_t* cond;

int main(int args, char **argv)
{
    pthread_mutex_t mutex_var;
    pthread_cond_t cond_var;

    mutex = &mutex_var;
    cond = &cond_var;

    pthread_mutex_init(mutex, NULL); 
    pthread_cond_init(cond, NULL);

    pthread_t threads[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; i++)
    {
        printf("Creating Thread %d....\n", i);

        int* id = malloc(sizeof(int));
        *id = i;

        if(0 != pthread_create(&threads[i], NULL, thread, (void *) id))
        {
            perror("Error while creating the threads");
            exit(1);
        }
    }

    for (int i = 0; i < NUM_THREADS; i++) 
    {
        pthread_join(threads[i], NULL);
    }

    return 0;
}


void* thread(void* idp)
{   
    int* id = (int*) idp;

    while (1)
    {
        sleep(*id+2); // Thread work

        pthread_mutex_lock(mutex);
            threads_running++;
        pthread_mutex_unlock(mutex);
        pthread_cond_broadcast(cond);

        printf("Thread %d WAIT\n", *id);
        fflush(stdout);

        // Let threads synchronize

        pthread_mutex_lock(mutex);
            while(threads_running != NUM_THREADS)
            {
                pthread_cond_wait(cond, mutex);
            }
        pthread_mutex_unlock(mutex);    

        printf("Thread %d WAKEUP\n", *id);
        fflush(stdout);

        // and continue

        pthread_mutex_lock(mutex);
            threads_running--;
        pthread_mutex_unlock(mutex);
    }
}

发生的事情是,有些人(通常是#9和一两个其他人)达到Thread %d WAKEUP但在其他人醒来之前threads_running已经小于NUM_THREADS

如何同步多个线程,以便它们一起继续? 我在围绕对变量的并行访问时遇到了一些麻烦。

2 个答案:

答案 0 :(得分:0)

我几秒钟后找到了答案:

  1. while(threads_running != NUM_THREADS)更改为while(threads_running != 0 && threads_running != NUM_THREADS)

  2. threads_running--;更改为threads_running = 0;

  3. 现在它完美无缺。

答案 1 :(得分:0)

我建议使用pthread_cond_signal()而不是pthread_cond_broadcast(cond); 因此,退出while循环的代码流如下所示。

        pthread_mutex_lock(mutex);
        while(threads_running != 0 && threads_running != NUM_THREADS)
        {
            pthread_cond_wait(cond, mutex);
        }
    pthread_cond_signal(cond);

所以最终代码如下:

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

#define NUM_THREADS 10

void* thread(void* idp);

int threads_running = 0;
pthread_mutex_t* mutex;
pthread_cond_t* cond;

int main(int args, char **argv)
{
    pthread_mutex_t mutex_var;
    pthread_cond_t cond_var;

    mutex = &mutex_var;
    cond = &cond_var;

    pthread_mutex_init(mutex, NULL); 
    pthread_cond_init(cond, NULL);

    pthread_t threads[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; i++)
    {
        printf("Creating Thread %d....\n", i);

        int* id = malloc(sizeof(int));
        *id = i;

        if(0 != pthread_create(&threads[i], NULL, thread, (void *) id))
        {
            perror("Error while creating the threads");
            exit(1);
        }
    }

    for (int i = 0; i < NUM_THREADS; i++) 
    {
        pthread_join(threads[i], NULL);
    }

    return 0;
}


void* thread(void* idp)
{   
    int* id = (int*) idp;

    while (1)
    {
        sleep(*id+2); // Thread work

        pthread_mutex_lock(mutex);
            threads_running++;
        pthread_mutex_unlock(mutex);

        printf("Thread %d WAIT\n", *id);
        fflush(stdout);

        // Let threads synchronize

        pthread_mutex_lock(mutex);
            while(threads_running != 0 && threads_running != NUM_THREADS)
            {
                pthread_cond_wait(cond, mutex);
            }
        pthread_cond_signal(cond);

        pthread_mutex_unlock(mutex);    

        printf("Thread %d WAKEUP\n", *id);
        fflush(stdout);

        // and continue
        pthread_mutex_lock(mutex);
            threads_running = 0;
        pthread_mutex_unlock(mutex);
    }
}