目录
简单的线程安全栈封装
#include <iostream>
#include <thread>
#include <mutex>
#include <stack>
#include <vector>
#include <exception>
using namespace std;
//异常处理
struct Stack_Empty :public exception
{
//重写了exception类中的what()函数,用于返回异常信息。
const char* what() const noexcept
{
return "栈为空";
}
};
//简单的线程安全栈的封装
template<class T>
class Thread_Safe_Stack
{
public:
Thread_Safe_Stack() {}
Thread_Safe_Stack(const Thread_Safe_Stack& other)
{
lock_guard<mutex> lock(other.mtx);
this->data = other.data;
}
//复制赋值运算符禁用
Thread_Safe_Stack& operator=(const Thread_Safe_Stack&) = delete;
//常用函数
bool isEmpty()
{
lock_guard<mutex> lock(mtx);
return data.empty();
}
size_t theSize()
{
lock_guard<mutex> lock(mtx);
return data.size();
}
//存取数据
void PushData(T value)
{
lock_guard<mutex> lock(mtx);
data.push(value);
printf("insertValue:%d\n", value);
}
void getData(T& value)
{
lock_guard<mutex> lock(mtx);
if (data.empty())//如果是空的则抛出异常
{
throw Stack_Empty();
}
else
{
value = data.top();
data.pop();
}
}
private:
mutable mutex mtx;
stack<T> data;
};
//测试函数
void insertData(Thread_Safe_Stack<int>& stack, int data)
{
stack.PushData(data);
}
void popData(Thread_Safe_Stack<int>& stack)
{
try
{
int value = 0;
stack.getData(value);
printf("data:%d\n", value);
}
catch(Stack_Empty one)//为空捕获
{
printf("%s\n", one.what());
}
}
int main()
{
vector<thread> t;
Thread_Safe_Stack<int> test;
for (int i = 0; i < 5000; i++)
{
t.push_back(thread(insertData, ref(test), i));
t.push_back(thread(popData, ref(test)));
}
for (auto& v:t)//线程是禁止拷贝的,所以用&
{
v.join();
}
cout << "size:" << test.theSize() << endl;
return 0;
}
上面的代码为什么不用解锁?
在构造函数和成员函数中使用了lock_guard<mutex> lock(mtx),这是一个RAII(Resource Acquisition Is Initialization)技术【资源获取即初始化】,它在构造时会锁定互斥量,析构时会自动解锁互斥量。所以不需要手动解锁。
输出结果为什么不为0
如果最后输出的size的结果不为0,假设是29个,表示在进行多线程的插入和弹出操作后,栈中剩余的元素个数是29个。这可能是由于在插入和弹出操作之间的竞争情况下,一些数据被其他线程弹出,但还有29个数据留在栈中。