我已经学习了一段时间的C ++标准库多线程,作为练习,我想使用互斥锁和条件变量来创建一个线程安全的堆栈。这是我上课的时间:
#ifndef THREADSAFE_STACK_H_
#define THREADSAFE_STACK_H_
#include <mutex>
#include <condition_variable>
#include <stack>
#include <memory>
template <typename T> class threadsafe_stack
{
public:
mutable std::mutex mut;
std::stack<T> st;
std::condition_variable cond;
public:
threadsafe_stack() = default;
threadsafe_stack(const threadsafe_stack &s);
threadsafe_stack(threadsafe_stack &&s);
threadsafe_stack& operator=(const threadsafe_stack &s);
threadsafe_stack& operator=(threadsafe_stack &&s);
void push(const T &t);
void push(T &&t);
bool try_pop(T &t);
std::shared_ptr<T> try_pop();
void wait_and_pop(T &t);
std::shared_ptr<T> wait_and_pop();
typename std::stack<T>::size_type size() const;
bool empty() const;
};
template <typename T> threadsafe_stack<T>::threadsafe_stack(const threadsafe_stack &s)
{
std::lock(mut, s.mut);
std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
st = s.st;
}
template <typename T> threadsafe_stack<T>::threadsafe_stack(threadsafe_stack &&s)
{
std::lock(mut, s.mut);
std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
st = std::move(s.st);
}
template <typename T> threadsafe_stack<T>& threadsafe_stack<T>::operator=(const threadsafe_stack &s)
{
if (this == &s)
return *this;
std::lock(mut, s.mut);
std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
s = s.st;
return *this;
}
template <typename T> threadsafe_stack<T>& threadsafe_stack<T>::operator=(threadsafe_stack &&s)
{
std::lock(mut, s.mut);
std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
s = std::move(s.st);
}
template <typename T> void threadsafe_stack<T>::push(const T &t)
{
std::lock_guard<std::mutex> lock(mut);
st.push(t);
cond.notify_one();
}
template <typename T> void threadsafe_stack<T>::push(T &&t)
{
std::lock_guard<std::mutex> lock(mut);
st.push(std::move(t));
cond.notify_one();
}
template <typename T> bool threadsafe_stack<T>::try_pop(T &t)
{
std::lock_guard<std::mutex> lock(mut);
if (st.empty())
return false;
t = st.top();
st.pop();
return true;
}
template <typename T> std::shared_ptr<T> threadsafe_stack<T>::try_pop()
{
std::lock_guard<std::mutex> lock(mut);
if (st.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> result(new T{st.top});
st.pop();
return result;
}
template <typename T> void threadsafe_stack<T>::wait_and_pop(T &t)
{
std::unique_lock<std::mutex> lock(mut);
cond.wait(lock, [this]{ return !st.empty(); });
t = st.top();
st.pop();
}
template <typename T> std::shared_ptr<T> threadsafe_stack<T>::wait_and_pop()
{
std::unique_lock<std::mutex> lock(mut);
cond.wait(lock, [this]{ return !st.empty(); });
std::shared_ptr<T> result(new T{ st.top });
st.pop();
return result;
}
template <typename T> typename std::stack<T>::size_type threadsafe_stack<T>::size() const
{
std::lock_guard<std::mutex> lock(mut);
return st.size();
}
template <typename T> bool threadsafe_stack<T>::empty() const
{
std::lock_guard<std::mutex> lock(mut);
return st.empty();
}
#endif
然后我想在一个像这样的简单程序中测试它:
#include <iostream>
#include <condition_variable>
#include <ctime>
#include <chrono>
#include <thread>
#include "threadsafe_stack.h"
threadsafe_stack<int> data_stack;
void process_data()
{
while (true)
{
int val = 0;
data_stack.wait_and_pop(val);
std::cout << val << " ";
}
}
int main()
{
std::thread processor(process_data);
processor.detach();
int values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 10; i++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
data_stack.push(values[i]);
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
system("pause");
return 0;
}
输出结果为:
1 2 3 4 5 6 7 8 9 10 Press any key to continue . . .
f:\dd\vctools\crt\crtw32\stdcpp\thr\mutex.c(40): mutex destroyed while busy
在我按任意键或尝试关闭控制台后立即出现第二行。除了附加消息,我得到一个错误(我猜是未处理的异常?)听起来像我在退出程序时使用互斥锁但它不应该因为条件变量wait应该在等待时解锁它。我很无能。
答案 0 :(得分:1)
这是因为程序退出,这会破坏全局变量。如果你想等到程序完成工作,你需要加入底部的processor
线程(而不是分离它)。
条件变量只能使其他线程休眠,而不是主线程。