c++ - cpp线程连接如果两个线程相互依赖应该使用连接导致死锁
问题描述
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
std::mutex lock_bar_;
std::mutex lock_foo_;
int n = 3;
void foo() {
for (int i = 0; i < n; i++) {
lock_foo_.lock();
// printFoo() outputs "foo". Do not change or remove this line.
std::cout << "1\n";
lock_bar_.unlock();
}
}
void bar() {
for (int i = 0; i < n; i++) {
lock_bar_.lock();
// printBar() outputs "bar". Do not change or remove this line.
std::cout << "2\n";
lock_foo_.unlock();
}
}
int main(){
lock_bar_.lock();
std::thread t1{foo};
std::thread t2{bar};
t1.join(); // line 1
std::cout << "333\n"; // line 2
t2.join(); // line 3
std::cout << "3\n"; // line 4
}
结果是
1
2
1
2
1
2
333
3
或者
1
2
1
2
1
333
2
3
我的问题是:为什么这个程序可以不死锁地运行?
join() 实际上是如何工作的?
当程序执行第 1 行时,根据 cppreference https://en.cppreference.com/w/cpp/thread/thread/join
“阻塞当前线程,直到 *this 标识的线程完成执行。”
我的理解是主要的主题应该停止。它一直等到线程 t1 完成。然后执行第 2 行和其余的。但程序似乎执行第 1 行和第 3 行。当线程 t1 完成时,它运行第 2 行。当线程 t2 完成时,它执行第 4 行。我对 join() 感到困惑。
如果有人可以提供帮助,非常感谢
第一次编辑:
忽略原程序
新程序是
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
int n = 10;
bool first = true;
std::condition_variable cv1;
std::condition_variable cv2;
std::mutex m;
void foo() {
std::unique_lock<std::mutex> ul(m, std::defer_lock);
for (int i = 0; i < n; i++) {
ul.lock();
cv1.wait(ul, [&]()->bool {return first;} );
std::cout << "1\n";
// printFoo() outputs "foo". Do not change or remove this line.
first = !first;
ul.unlock();
cv2.notify_all();
}
}
void bar() {
std::unique_lock<std::mutex> ul(m, std::defer_lock);
for (int i = 0; i < n; i++) {
ul.lock();
cv2.wait(ul, [&]()->bool {return !first;} );
// printBar() outputs "bar". Do not change or remove this line.
std::cout << "2\n";
first = !first;
ul.unlock();
cv1.notify_all();
}
}
int main(){
std::thread t1{foo};
std::thread t2{bar};
t1.join();
std::cout << "3\n";
t2.join();
}
同样的问题
解决方案
你的线程做的工作很少。根据您的操作系统和 cpu 内核的数量,线程只会以固定的时间间隔切换。很有可能在t1.join
返回后t2
已经完成执行(您的第一个输出)。
如果您在线程中的循环中添加一些睡眠,您应该每次都会看到您的第二个输出,因为在返回t2
时仍将执行。t1.join
请注意,从最初未锁定互斥锁的线程解锁互斥锁具有未定义的行为:https ://en.cppreference.com/w/cpp/thread/mutex/unlock
推荐阅读
- flutter - app-flutter-openemr 初始化时出错
- java - BuildConfig 值在单元测试中不可用
- android - 如何使用 AIDL(不使用活动或片段)在客户端应用程序顶部显示服务的 UI?
- python - 如何编写处理不同类型列表的函数
- c# - 色盲和颜色。VS2019 文本编辑器的哪些元素与 C# 语言相关?
- c# - Fortify - 违反信任边界 - Asp.net(C#)- 字符串
- c# - 时间:2019-05-11 标签:c#ews find an email that only sent without save
- android - PluginApplicationException:无法应用插件类“FlutterPlugin”
- log4j - 在翻转场景中将错误的日期附加到 log4j 中的日志文件
- google-chrome-extension - 适用于 Chrome、Firefox、Safari 标准参考和工具的 Web 扩展(浏览器插件)(2021 年)