c - 同步中的 pthread_mutex_lock 问题
问题描述
我一直在研究在 C 中使用 pthread 库的代码。代码执行以下操作:
- Main 创建两个线程,每个线程都有自己的线程例程(函数)
- 一个线程(线程 1)生成一个随机数并将其分配给全局变量 x
- 然后另一个线程(线程2)基本上打印了全局变量的值
- 这个生成并打印 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;
}
我的问题是如何正确使用互斥锁以保持这两个线程之间的顺序而不使用其他任何东西。
解决方案
乍一看有两个问题:
- 线程的序列化不适用于互斥锁
- 在等待线程结束之前调用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;
}
推荐阅读
- html - 如何导航到不同页面中的部分
- python-3.x - 如何绘制最佳参数对应的随机森林树
- java - 无法实现检测输入是否为整数的系统
- mongodb - 无法使用 mongocompass 连接到谷歌云实例 mongo
- discord - 命令处理程序未正确显示
- spring - 将应用程序注释为 Eureka 服务器时,需要指定它不是客户端
- python - 广播多个二维数组作为另一个二维数组的单个元素
- swift - 快速如何以编程方式设置自动布局
- javascript - 在javascript / jQuery中使用数据库中的下拉值附加/复制表行
- batch-file - 使用批处理文件根据其内容重命名多个 JSON