c++ - c++ Linux中的线程无限期等待
问题描述
我们必须编写将创建两个线程的程序。第一个线程会从键盘请求字母,然后它会向等待它的第二个线程发送一个信号。然后它将这个字母改成大写字母,如果这个字母不是'E',它会向线程一发送另一个信号。什么会再次运行线程,直到您键入的字母不会是“e”。
两个线程之间的通信有点类似于打乒乓球,或者至少应该如此。
下面我添加一段我写的代码。它还没有完成,但有一个问题我无法修复或找到解决方案。当我尝试运行此代码时,它会卡住。看起来两个线程都在等待信号,所以什么都没有发生。
怎么了?
#include <iostream>
#include <fstream>
#include <string>
#include <pthread.h>
#include <stdlib.h>
using namespace std;
pthread_mutex_t mut;
pthread_cond_t dadam;
pthread_cond_t dudum;
char x;
void *first(void *arg) {
while(1) {
pthread_mutex_lock(&mut);
pthread_cond_wait(&dadam, &mut);
cout << "Type a letter\n";
cin >> x;
pthread_mutex_unlock(&mut);
pthread_cond_signal(&dudum);
}
}
void *second(void *arg) {
while(1) {
pthread_cond_wait(&dudum, &mut);
pthread_mutex_lock(&mut);
char y;
y = toupper(x);
cout << y << endl;
pthread_mutex_unlock(&mut);
pthread_cond_signal(&dadam);
}
}
int main()
{
pthread_t nun;
pthread_t nuno;
pthread_create(&nun, NULL, &first,NULL);
pthread_create(&nuno, NULL, &second,NULL);
pthread_cond_signal(&dadam);
pthread_join(nun, NULL);
pthread_join(nuno, NULL);
return 0;
}
解决方案
您不会初始化互斥锁或条件变量。它们具有静态持续时间,因此参与默认初始化,但不能保证这会产生可用状态。实现这一点的通用方法是使用pthread_cond_init()
and pthread_mutex_init()
,但如果默认值足够,那么您还可以使用初始化宏:
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dadam = PTHREAD_COND_INITIALIZER;
pthread_cond_t dudum = PTHREAD_COND_INITIALIZER;
您还尝试在dudum
不持有指定互斥锁的情况下等待 CV。调用时需要持有互斥锁pthread_cond_wait()
:
pthread_mutex_lock(&mut);
pthread_cond_wait(&dudum, &mut);
(不是相反)。
但主要问题似乎是您的实现中的竞争条件。
在其循环的每次迭代中,函数在继续之前first()
等待 CV ,并且在其循环的每次迭代中,函数在继续之前等待 CV 。如果您可以引导它,这可能会起作用,但是当您第一次启动这两个功能时,任何一个都不能继续等待以发出另一个正在等待的 CV 信号。您从主线程发出信号,但如果主线程在开始等待之前发送信号,则信号将丢失。dadam
second()
dudum
dadam
first()
不足:
建议:
- 正确初始化互斥锁和 CV。
- 修复函数中互斥范围的问题
second()
;和 - 在
main()
,在互斥锁的保护下执行线程创建(但不是连接);和 - 在函数中
first()
(仅)将 移动pthread_cond_wait()
到循环的末尾(确保适当地扩展互斥锁的范围),这样first()
就不必等待信号执行其第一次迭代;和 删除pthread_cond_signal()
frommain()
,因为它不再需要。
请注意,在pthread_cond_signal()
锁定目标 CV 的关联互斥锁的同时执行一段时间是安全的。不需要这样做,但有些人建议将其作为良好做法。
推荐阅读
- python - __init__() 为关键字参数“列”获取了多个值
- docker - Docker pypspark 集群容器没有从主机接收到 kafka 流?
- android - onResume 中的生物识别提示抛出 FragmentManager 已经在执行事务
- javascript - 当标题具有“粘性”类时,如何更改原始颜色?
- python - mac:通过 pyenv 使用 python 3 会引发导入错误
- python - Django - 根据它们的 ForeignKey 过滤对象但有多种选择?
- java - 无法从 firebaseRealtimeDatabase 和 firebaseStorage 检索数据和图像(V/FA:不活动,与服务断开连接)
- java - java中运行时执行的过程是什么,JVM在运行时如何检查数组类型?
- sql - SQL左连接降低性能
- jquery - 使用 codeigniter 填充 ajax 数据表