C++线程安全容器stack和queue的使用详细介绍
什么是线程安全容器
线程安全容器是可以支持在多个线程并发访问的STL容器。在多线程程序中使用线程安全容器可以保证数据操作的正确性和安全性。
为什么需要线程安全容器
在并发环境中,多个线程可能同时访问同一资源。对于非线程安全的容器,在多线程的情况下容易出现数据竞争、死锁等问题。线程安全容器可以避免这种问题的发生,保证程序的正确性。
C++线程安全容器
C++ STL库提供了一些线程安全容器,包括std::stack
和std::queue
,它们都是基于顺序容器实现的。这些容器提供了多个线程的并发访问功能。
std::stack
std::stack
是一个后进先出(LIFO)的容器。将元素插入std::stack
中时,总是插入到栈顶(最近插入的元素为栈顶元素),删除元素时,总是从栈顶弹出。
示例1
下面是一个使用std::stack
的简单示例程序:
#include <iostream>
#include <stack>
#include <thread>
void foo(std::stack<int>& s) {
for (int i=0; i<5; ++i) {
s.push(i);
std::cout << "push: " << i << std::endl;
}
}
void bar(std::stack<int>& s) {
while (!s.empty()) {
std::cout << "pop: " << s.top() << std::endl;
s.pop();
}
}
int main() {
std::stack<int> s;
std::thread t1(foo, std::ref(s));
std::thread t2(bar, std::ref(s));
t1.join();
t2.join();
return 0;
}
上述程序中,我们创建了一个std::stack
对象s
,然后创建了两个线程t1
和t2
,分别调用foo
和bar
函数。在foo
函数中,我们向s
中插入5个元素;在bar
函数中,我们从s
中不断取出元素,直到栈为空。注意,我们在调用foo
和bar
函数时,要将s
对象传递给它们作为参数。
运行上述程序,可以看到,两个线程正确地对同一个std::stack
对象进行了并发访问,没有发生任何错误。
示例2
下面是另一个std::stack
的示例程序,演示了如何在多个线程中同时对栈进行修改操作:
#include <iostream>
#include <stack>
#include <thread>
template<typename T>
void safe_push(std::stack<T>& s, T val) {
std::lock_guard<std::mutex> lock(s.mtx);
s.stk.push(val);
}
template<typename T>
T safe_pop(std::stack<T>& s) {
std::lock_guard<std::mutex> lock(s.mtx);
if (s.stk.empty()) {
return T();
}
T val = s.stk.top();
s.stk.pop();
return val;
}
template<typename T>
size_t safe_size(std::stack<T>& s) {
std::lock_guard<std::mutex> lock(s.mtx);
return s.stk.size();
}
template<typename T>
bool safe_empty(std::stack<T>& s) {
std::lock_guard<std::mutex> lock(s.mtx);
return s.stk.empty();
}
template<typename T>
void print_stack(std::stack<T>& s) {
std::lock_guard<std::mutex> lock(s.mtx);
while (!s.stk.empty()) {
std::cout << s.stk.top() << " ";
s.stk.pop();
}
std::cout << std::endl;
}
struct Stack {
std::mutex mtx;
std::stack<int> stk;
};
void foo(Stack& s) {
for (int i=0; i<10; ++i) {
safe_push(s.stk, i*10);
std::cout << "push: " << i*10 << std::endl;
}
}
void bar(Stack& s) {
for (int i=0; i<5; ++i) {
std::cout << "pop: " << safe_pop(s.stk) << std::endl;
}
}
int main() {
Stack s;
std::thread t1(foo, std::ref(s));
std::thread t2(bar, std::ref(s));
t1.join();
t2.join();
std::cout << "size: " << safe_size(s.stk) << std::endl;
if (safe_empty(s.stk)) {
std::cout << "stack is empty" << std::endl;
}
return 0;
}
上述程序中,我们定义了一个Stack
结构体,其中包含了一个std::mutex
对象和一个std::stack
对象。我们通过定义一些线程安全的操作(比如safe_push
、safe_pop
等)来对std::stack
进行访问。在foo
函数中,我们插入了10个元素;在bar
函数中,我们弹出了一些元素。注意,我们在对std::stack
进行修改时,必须使用std::lock_guard<std::mutex>
对其加锁。
运行上述程序,可以看到,在多个线程同时操作同一个std::stack
对象时,线程安全容器可以正确地保证数据的一致性和安全性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++线程安全容器stack和queue的使用详细介绍 - Python技术站