c-同步中的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 = %dn" , 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 = %dn" , 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;
}

我的问题是如何正确使用互斥,以便在不使用其他任何东西的情况下维护这两个线程之间的顺序。

第一眼看到的两个问题:

  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 = %dn" , 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 = %dn" , 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;
}

不是一个完整的答案,但我只是想明确地说一些其他答案中隐含的东西。

。。。如何正确地使用互斥以维护这两个线程之间的顺序。。。

这不是互斥的目的。互斥是错误的工具。

当您希望一个线程等待另一个线程执行某项操作时,可以使用的最低级别工具称为条件变量。在posix线程库(pthreads(中,您使用一个pthread_cond_t变量和对其进行操作的各种pthread_cond_...(...)函数:

https://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread.h.html


但也要注意:人们通常会使用一些公认的、更高级别的模式来解决你的问题。例如,谷歌的";阻塞队列">

根据这个问题的大多数答案和评论,我认为互斥锁不是维护两个线程之间顺序的正确工具。然而,在我的导师的帮助下,他向我展示了一个解决这种问题的技巧,这个技巧是首先锁定其中一个关键部分(由线程2执行的关键部分(,然后在另一个线程(线程1(中解锁该部分

这就是新代码看起来像的样子

#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){
pthread_mutex_lock(&m1);
x = (rand() % 10) + 1; // generates a random number between 1 and 10    
printf("generator >> x = %dn" , x);
// 2- unlock the critical section of the printing thread
pthread_mutex_unlock(&m2);
}

void * thread2(void * arg){
pthread_mutex_lock(&m2);
printf("printer >> x = %dn" , x);
pthread_mutex_unlock(&m1);
}
int main(void) 
{   
srand(time(NULL));
pthread_mutex_init(&m1, NULL);
pthread_mutex_init(&m2, NULL);
// 1- locking the critical section of the printing thread
pthread_mutex_lock(&m2);
for(int i = 0 ; i < 5 ; i++) {
pthread_create(&t[1], NULL, thread1, NULL);
pthread_create(&t[0], NULL, thread2, NULL);
}
pthread_exit(NULL);
pthread_mutex_destroy(&m1);
pthread_mutex_destroy(&m2);
return 0;
}

相关内容

  • 没有找到相关文章

最新更新