我在linux Debian系统上使用下面的foo.cpp代码:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <thread>
std::mutex mtx;
std::condition_variable cvar;
long next = 0;
void doit(long index){
std::unique_lock<std::mutex> lock(mtx);
cvar.wait(lock, [=]{return index == next;});
std::cout<< index << std::endl;
++next;
mtx.unlock();
cvar.notify_all();
return;
}
int main()
{
long n=50;
for (long i=0; i < n; ++i)
std::thread (doit,i).detach();
while(next != n)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return(0);
}
我用以下代码编译它:
g ++ -std = c ++ 14 -pthread -o foo foo.cpp
它设计用于触发50个已分离的线程,这些线程由函数doit中的互斥锁和condition_variable控制,因此它们按顺序执行互斥锁。
它大部分时间都在工作,将数字00到49写入屏幕,然后终止。
但是,它有两种偶然的失败模式:
失败模式1 :升级到某个任意数字后&lt; 50,它因错误而中止:
foo:../ nptl / pthread_mutex_lock.c:80:__ pthread_mutex_lock:断言`mutex-&gt; __ data .__ owner == 0'失败。
失败模式2 :升级到某个任意数字后&lt; 50,它挂起,必须用ctrl-C杀死才能返回终端提示符。
我很感激有关此行为原因的任何建议,以及我如何解决这个问题。
=============================================== ==========================
编辑:好的,所以这是一个正在修改的版本。我修复了两个错误,并将锁定名称从“锁定”更改为“lk”以减少混淆。谢谢你的帮助。
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
std::mutex mtx;
std::condition_variable cvar;
long next = 0;
void doit(long index){
std::unique_lock<std::mutex> lk(mtx);
cvar.wait(lk, [=]{return index == next;});
std::cout<< index << std::endl;
++next;
lk.unlock();
cvar.notify_all();
return;
}
int main()
{
long n=50;
for (long i=0; i < n; ++i)
std::thread (doit,i).detach();
{
std::unique_lock<std::mutex> lk(mtx);
cvar.wait(lk, [=]{return n == next;});
}
return(0);
}
答案 0 :(得分:0)
我不建议拆分线程,因为在此之后你无法加入它们。 如果你真的想这样做,那么使用条件变量来同步下一次的数据。
void doit(long index){
std::unique_lock<std::mutex> lock(mtx);
cvar.wait(lock, [=]{return index == next;});
std::cout<< index << std::endl;
++next;
cvar.notify_all();
return;
}
int main()
{
long n=50;
for (long i=0; i < n; ++i)
std::thread (doit,i).detach();
//here you wait for the last thread to finish
{
std::unique_lock<std::mutex> lock(mtx);
cvar.wait(lock, [=]{return n == next;});
}
return(0);
}
如果你可以让你的线程可以连接,你可以编写更简单的代码。
std::mutex mtx;
std::condition_variable cvar;
long next = 0;
void doit(long index){
std::unique_lock<std::mutex> lock(mtx);
//this guarantees the order in which are being executed
cvar.wait(lock, [=]{return index == next;});
std::cout<< index << std::endl;
++next;
cvar.notify_all();//wakes all the thread, only the one with index=next will be executed
return;
}
int main()
{
long n=50;
std::vector<std::thread> workers;
for (long i=0; i < n; ++i){
workers.emplace_back(std::thread (doit,i));
}
//this guarantees your threads are all finished at the end of this block
for (auto& t : workers) {
t.join();
}
return(0);
}
答案 1 :(得分:-1)
为什么不保持简单?
int main() {
long n = 50;
std::vector<std::thread> threads;
for (long i = 0; i < n; ++i)
threads.emplace_back([=]() { std::cout << i << std::endl; });
for (const auto& t : threads) {
t.join();
}
return 0;
}
答案 2 :(得分:-1)
试试这个片段:你不应该使用mtx.unlock()并让condition_variable完成这项工作。还可以使用std :: ref将函数参数传递给线程。
std::mutex mtx;
std::condition_variable cvar;
bool ready = true;
void doit(long index) {
std::unique_lock<std::mutex> lock(mtx);
cvar.wait(lock, [=] {return ready == true; });
ready = false;
std::cout << index << std::endl;
ready = true;
cvar.notify_all();
return;
}
int main()
{
long n = 50;
for (long i = 0; i < n; ++i)
std::thread(doit, std::ref(i)).detach();
std::this_thread::sleep_for(std::chrono::seconds(3));
return(0);
}
答案 3 :(得分:-1)
std:: unique_lock
是RAII对象。在一个范围内宣布它并将您的关注投入到风中。这就是问题:在doit调用mtx.unlock()之后,有时候下一个语句cvar.notify_all()会立即用(new)next == index唤醒线程。该线程将获取互斥锁。当doit返回时,锁析构函数会尝试释放互斥锁,但它由另一个线程持有。灾难随之而来。以下是doit():
void doit(long index) {
{
std::unique_lock<std::mutex> lock(mtx);
cvar.wait(lock, [=] {return index == next; });
++next;
std::cout << index << std::endl;
}
cvar.notify_all();
return;
}