首页 > 解决方案 > 同步中的 pthread_mutex_lock 问题

问题描述

我一直在研究在 C 中使用 pthread 库的代码。代码执行以下操作:

  1. Main 创建两个线程,每个线程都有自己的线程例程(函数)
  2. 一个线程(线程 1)生成一个随机数并将其分配给全局变量 x
  3. 然后另一个线程(线程2)基本上打印了全局变量的值
  4. 这个生成并打印 x 的随机值的操作重复了 5 次

预期输出:

generator thread >> x = 5
printer thread >> x = 5
generator thread >> x = 9
printer thread >> x = 9
generator thread >> x = 7
printer thread >> x = 7
generator thread >> x = 3
printer thread >> x = 3
generator thread >> x = 2
printer thread >> x = 2

但是,输出以随机顺序出现,有时打印机首先执行,或者其中一个线程在另一个线程执行之前多次执行。

例如:

$ ./mutex.out 
generator >> x = 7
generator >> x = 10
generator >> x = 4
generator >> x = 7
generator >> x = 10
printer >> x = 7
printer >> x = 10
printer >> x = 10
printer >> x = 10
printer >> x = 10
$ ./mutex.out 
printer >> x = 0
printer >> x = 0
printer >> x = 0
printer >> x = 0
printer >> x = 0
generator >> x = 9
generator >> x = 2
generator >> x = 1
generator >> x = 3
generator >> x = 7

我为这个问题编写的代码:

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


#define NUMTHRDS 2
pthread_t t [ NUMTHRDS];
pthread_mutex_t m1, m2; 
int x = 0; 

void *thread1(void *arg){
    for(int i = 0 ; i < 5 ; i++){
        pthread_mutex_lock(&m2); 
        pthread_mutex_lock(&m1); 
        x = (rand() % 10) + 1; // generates a random number between 1 and 10    
        printf("generator >> x = %d\n" , x);

        pthread_mutex_unlock(&m1); 
        pthread_mutex_unlock(&m2);
    }
}


void * thread2(void * arg){
    for(int i = 0 ; i < 5 ; i++){
        pthread_mutex_lock(&m1); 
        pthread_mutex_lock(&m2); 
        printf("printer >> x = %d\n" , x);
        pthread_mutex_unlock(&m2); 
        pthread_mutex_unlock(&m1);
    }
}

int main(void) 
{   
    srand(time(NULL));

    pthread_mutex_init(&m1, NULL);
    pthread_mutex_init(&m2, NULL);
    
    pthread_create(&t[1], NULL, thread1, NULL);
    pthread_create(&t[0], NULL, thread2, NULL);

    pthread_mutex_destroy(&m1);
    pthread_mutex_destroy(&m2);

    pthread_exit(NULL);

    return 0;

}

我的问题是如何正确使用互斥锁以保持这两个线程之间的顺序而不使用其他任何东西。

标签: cmultithreadingpthreadsmutex

解决方案


乍一看有两个问题:

  1. 线程的序列化不适用于互斥锁
  2. 在等待线程结束之前调用pthread_mutex_destroy()使得后者可能使用已销毁的互斥锁

这是使用条件变量序列化线程并使用pthread_join()正确终止的建议:

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


#define NUMTHRDS 2
pthread_t t [ NUMTHRDS];
pthread_mutex_t m1, m2; 
int x = 0; 
pthread_cond_t cond1, cond2;
int gen, prt;


void *thread1(void *arg){
  for(int i = 0 ; i < 5 ; i++){
    pthread_mutex_lock(&m1);
    if (!gen) {
      pthread_cond_wait(&cond1, &m1);
    }

    x = (rand() % 10) + 1; // generates a random number between 1 and 10    
    printf("generator >> x = %d\n" , x);

    gen = 0;
    pthread_mutex_unlock(&m1);

    // Wake up printer
    pthread_mutex_lock(&m2);
    prt = 1;
    pthread_cond_signal(&cond2);
    pthread_mutex_unlock(&m2);

  }
}


void * thread2(void * arg){
  for(int i = 0 ; i < 5 ; i++){
    pthread_mutex_lock(&m2); 
    if (!prt) {
      pthread_cond_wait(&cond2, &m2);
    }
    printf("printer >> x = %d\n" , x);
    pthread_mutex_unlock(&m2); 

    prt = 0;
    pthread_mutex_unlock(&m2);

    // Wake up generator
    pthread_mutex_lock(&m1);
    gen = 1;
    pthread_cond_signal(&cond1);
    pthread_mutex_unlock(&m1);
  }
}

int main(void) 
{   
  srand(time(NULL));

  pthread_mutex_init(&m1, NULL);
  pthread_mutex_init(&m2, NULL);

  pthread_cond_init(&cond1, NULL);
  pthread_cond_init(&cond2, NULL);

  pthread_create(&t[1], NULL, thread1, NULL);
  pthread_create(&t[0], NULL, thread2, NULL);

  // Wake up generator
  printf("Waking up generator...\n");
  pthread_mutex_lock(&m1);
  gen = 1;
  pthread_cond_signal(&cond1);
  pthread_mutex_unlock(&m1);

  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);

  pthread_mutex_destroy(&m1);
  pthread_mutex_destroy(&m2);

  pthread_cond_destroy(&cond1);
  pthread_cond_destroy(&cond2);

  return 0;

}

推荐阅读