让我们了解下一个代码示例:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <deque>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
std::deque<int> queue;
void Inserter()
{
int count = 10;
while (count >= 0)
{
std::unique_lock<std::mutex> lock(mtx);
queue.push_back(count);
--count;
lock.unlock();
}
}
void Consumer()
{
int count = 10, got;
while (count >= 0)
{
std::unique_lock<std::mutex> lock(mtx);
if (!queue.empty())
{
got = queue.back();
queue.pop_back();
std::cout << "We got: " << got << std::endl;
--count;
lock.unlock();
}
else
{
lock.unlock();
}
}
}
int main()
{
std::thread t1(Inserter);
std::thread t2(Consumer);
std::cin.get();
return 0;
}
当我运行这个程序时,我得到“中止”,但我不应该。 我在这里看到中止的唯一原因是当我离开锁定锁而没有打开它时 - 但没有任何理由让锁保持锁定,因为在我经过的每个循环之后我打开锁。
你认为原因是什么?
答案 0 :(得分:1)
您不能在主程序中调用std::thread::join
。当t2
超出范围时,你会调用它的析构函数,并且由于你还没有加入该线程,它会导致中止。
顺便说一句,您不需要致电lock.unlock()
。 std::unique_lock
的重点是它会在对象被破坏时自动执行。 (将got
声明为从队列中获取值的位置会更加清晰。)
所以你的代码应该是这样的:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <deque>
std::mutex mtx;
std::deque<int> queue;
void Inserter()
{
for (int count = 10; count >= 0; --count)
{
std::unique_lock<std::mutex> lock(mtx);
queue.push_back(count);
}
}
void Consumer()
{
for (int count = 10; count >= 0; )
{
std::unique_lock<std::mutex> lock(mtx);
if (!queue.empty())
{
const int got = queue.back();
queue.pop_back();
std::cout << "We got: " << got << std::endl;
--count;
}
}
}
int main()
{
std::thread t1(Inserter);
std::thread t2(Consumer);
t1.join();
t2.join();
std::cin.get();
return 0;
}
调用join
的要求是因为一个常见的习惯用法是使Inserter
成为派生自std::thread
的类,并使Inserter
构造函数传递合适的线程函数到std::thread
构造函数。如果类包含线程方法访问的成员变量,那么如果线程方法在对象被破坏后继续运行则会很糟糕。该标准要求您通过调用join
(在这种情况下线程方法已完成)或通过调用detach
来避免这种情况(在这种情况下,您有责任确保不要使用Maven
。 t访问超出范围的变量。)
答案 1 :(得分:0)
要解决此问题,您需要在两个线程上调用std::thread::join
int main(){
std::thread t1(Inserter);
std::thread t2(Consumer);
t1.join();
t2.join();
return 0;
}
演示:here