繁体   English   中英

在C中使用Pthreads互斥锁和条件变量进行同步

[英]Synchronization using Pthreads mutex and conditional variables in C

我试图创建两个类似于TaskA和TaskB的线程。 TaskA和TaskB都进行某种形式的计算,因此对于本篇文章来说不是很有趣。 TaskA和TaskB必须执行10次才能覆盖整个数组。 TaskA具有输入AA和输出BB。 BB也是TaskB的输入。 CC是TaskB的输出。 因为BB是由taskA编写的,而由taskB读取的,所以我们需要互斥锁。

我想实现的行为是,当TaskA在i上进行操作时,TaskB在i-1上并行进行操作,其中i是要处理的数组数。 我想避免TaskB为每个i等待TaskA完成。

这里的问题是我陷入了僵局。 ThreadA和ThreadB代表TaskA和TaskB。 为了简化起见,我删除了所有计算,只留下了同步指令。 导致死锁的原因是,在线程B处于等待CV [0]的状态之前,ThreadA发出了条件变量CV [0]的信号。

您是否知道消除死锁的任何方法,但没有TaskA等待TaskB完成,反之亦然。 理想情况下,当TaskA在阵列i上运行时,TaskB应该在阵列i-1上运行。

/* Includes */
#include <unistd.h>     /* Symbolic Constants */
#include <sys/types.h>  /* Primitive System Data Types */ 
#include <errno.h>      /* Errors */
#include <stdio.h>      /* Input/Output */
#include <stdlib.h>     /* General Utilities */
#include <pthread.h>    /* POSIX Threads */
#include <string.h>     /* String handling */
#include <semaphore.h>  /* Semaphore */
#include <stdint.h>

#define ARRAY_SIZE 2048*2400
#define DEBUG
//#define CHECK_RESULTS

pthread_mutex_t mutex[10];
pthread_cond_t cv[10];

/* prototype for thread routine */
void threadA ( void *ptr );
void threadB ( void *ptr );


struct thread_arg
{
    uint32_t *in;
    uint32_t *out;
    uint32_t ID;    
};

int main()
{

    pthread_t pthA;
    pthread_t pthB;
   //Memory allocation 
    uint32_t *AA = malloc(10*ARRAY_SIZE*sizeof(uint32_t)); 
    uint32_t *BB = malloc(10*ARRAY_SIZE*sizeof(uint32_t));
    uint32_t *CC = malloc(10*ARRAY_SIZE*sizeof(uint32_t)); 
    unsigned int j,i;

    // THread Arguments
    struct thread_arg arguments[2];
    arguments[0].in  = AA;
    arguments[0].out = BB;
    arguments[0].ID  = 1;
    arguments[1].in  = BB;
    arguments[1].out = CC;
    arguments[1].ID  = 2;
    //Init arguments data
    for (j=0;j<10;j++)
    {
        for (i=0;i<ARRAY_SIZE;i++)
        {
            AA[j*ARRAY_SIZE+i] = i;
            BB[j*ARRAY_SIZE+i] = 0;
            CC[j*ARRAY_SIZE+i] = 99 ; 
        }
    }   

    //Semaphore and conditional variables init
    for (i=0;i<10;i++){
        pthread_mutex_init(&mutex[i], NULL);
        pthread_cond_init (&cv[i], NULL);

    }

    pthread_create (&pthA, NULL, (void *) &threadA, (void *) &arguments[0]);
    pthread_create (&pthB, NULL, (void *) &threadB, (void *) &arguments[1]);

    pthread_join(pthA, NULL);
    pthread_join(pthB, NULL);

    // Destroy Semaphores and CVs
    for (i=0;i<10;i++)
    {
        pthread_mutex_destroy(&mutex[i]);
        pthread_cond_destroy(&cv[i]); 
    }       
    // Checking results 

    exit(0);
} /* main() */





void threadA ( void *ptr )
{
    int i; 
    struct thread_arg *arg = (struct thread_arg *) ptr;
    for (i=0;i<10;i++)
    {
        pthread_mutex_lock(&mutex[i]);
        printf("TA: LOCK_M%d  \n",i);
        pthread_cond_signal(&cv[i]);
        printf("TA: SIG_CV%d\n",i);
        pthread_mutex_unlock(&mutex[i]);
        printf("TA: UNL_M%d\n",i);
    }   
    pthread_exit(0); /* exit thread */
}




void threadB ( void *ptr )
{
    int i; 
    struct thread_arg *arg = (struct thread_arg *) ptr;

    for (i=0;i<10;i++)
    {
        pthread_mutex_lock(&mutex[i]);
        printf("TB: WAIT_CV%d\n",i,i);
        pthread_cond_wait(&cv[i], &mutex[i]);
        printf("TB CV%d_PASSED\n",i);
        pthread_mutex_unlock(&mutex[i]);
        printf("TB UNL_M%d \n",i);
    }

  pthread_exit(NULL);
}

正如WhozCraig所说,条件变量需要与某个共享状态(称为谓词)上的条件配对。 互斥锁用于保护共享状态。

在此示例中,您的共享状态可以是一个整数,其中包含ThreadA产生的BB[]的最高索引。 然后,ThreadB等待该数字达到它要读取的索引。 在这种设计中,您只需要一个互斥锁和一个条件变量。 全局变量将是:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
int BB_ready = -1;  /* Protected by 'mutex' */

(使用静态PTHREAD_*_INITIALIZER初始化程序意味着您无需费心pthread_*_init()pthread_*_destroy() )。

这样,ThreadA中的循环将是:

for (i=0;i<10;i++)
{
    /* Process AA[i] into BB[i] here */

    /* Now mark BB[i] as ready */
    pthread_mutex_lock(&mutex);
    printf("TA: LOCK_M%d  \n",i);
    BB_ready = i;
    pthread_cond_signal(&cv);
    printf("TA: SIG_CV%d\n",i);
    pthread_mutex_unlock(&mutex);
    printf("TA: UNL_M%d\n",i);
}

..和ThreadB中:

for (i=0;i<10;i++)
{
    /* Wait for BB[i] to be ready */
    pthread_mutex_lock(&mutex);
    printf("TB: WAIT_CV%d\n",i);
    while (BB_ready < i)
        pthread_cond_wait(&cv, &mutex);
    printf("TB CV%d_PASSED\n",i);
    pthread_mutex_unlock(&mutex);
    printf("TB UNL_M%d \n",i);

    /* Now process BB[i] into CC[i] here */
}

请注意,只要共享状态发生更改,就会调用pthread_cond_signal() ,这将使另一个线程唤醒并重新检查该状态(如果正在等待)。

等待线程始终循环运行,检查状态,如果状态尚未准备就绪,则等待条件变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM