C++线程安全容器stack和queue的使用详细介绍

目录

C++线程安全容器stack和queue的使用详细介绍

什么是线程安全容器

为什么需要线程安全容器

C++线程安全容器

std::stack

示例1

示例2


C++线程安全容器stack和queue的使用详细介绍

什么是线程安全容器

线程安全容器是可以支持在多个线程并发访问的STL容器。在多线程程序中使用线程安全容器可以保证数据操作的正确性和安全性。

为什么需要线程安全容器

在并发环境中,多个线程可能同时访问同一资源。对于非线程安全的容器,在多线程的情况下容易出现数据竞争、死锁等问题。线程安全容器可以避免这种问题的发生,保证程序的正确性。

C++线程安全容器

C++ STL库提供了一些线程安全容器,包括std::stackstd::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,然后创建了两个线程t1t2,分别调用foobar函数。在foo函数中,我们向s中插入5个元素;在bar函数中,我们从s中不断取出元素,直到栈为空。注意,我们在调用foobar函数时,要将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_pushsafe_pop等)来对std::stack进行访问。在foo函数中,我们插入了10个元素;在bar函数中,我们弹出了一些元素。注意,我们在对std::stack进行修改时,必须使用std::lock_guard<std::mutex>对其加锁。

Note: 这里虽然说是安全容器,但是使用时还是需要自己添加互斥锁来保护,并不是真正的可以直接使用的安全容器。

请注明出处:C++线程安全容器stack和queue的使用详细介绍 - Python技术站

1. C++ STL(Standard Template Library)是C++标准库的一部分,提供了丰富的模板类和函数,用于简化常见的编程任务。STL的设计目标是提供高效、可重用和通用的数据结构和算法。它包括容器、算法和迭代器三个主要组件。 2. 适配器栈和队列的内部实现及使用: - 适配器栈(stack)是一种后进先出(LIFO)的数据结构。它基于双端队列(deque)实现,可以使用 push、pop 和 top 等操作进行元素的入栈、出栈和访问操作。 - 适配器队列(queue)是一种先进先出(FIFO)的数据结构。它也基于双端队列(deque)实现,可以使用 push、pop 和 front 等操作进行元素的入队、出队和访问操作。 3. 字符串容器 string 的实现及使用: - 字符串容器 string 是基于动态数组实现的,提供了一系列对字符串进行操作的成员函数,如插入、删除、查找、替换等。它还支持重载的运算符,使得字符串可以像基本类型一样进行操作。 4. 容器 vector 和 list 的使用及区别: - vector 是一个动态数组,支持随机访问,插入和删除元素的开销较大,适用于需要频繁访问元素的场景。 - list 是一个双向链表,不支持随机访问,插入和删除元素的开销较小,适用于需要频繁插入和删除元素的场景。 5. 关联容器 set 和 map 的内部实现及使用和区别: - set 是一个有序的容器,其中的元素是唯一的,内部实现通常是红黑树。 - map 是一个有序的键值对容器,其中的键是唯一的,内部实现通常也是红黑树。map 中的每个元素都是一个键值对,可以通过键来访问对应的值。 6. 迭代器是 STL 中的一个重要概念,用于遍历容器中的元素。它提供了一种统一的访问方式,使得算法可以独立于容器进行操作。 7. STL 内置算法函数(如 sort、find 等)是为了方便对容器进行常见操作而提供的函数。sort 用于对容器中的元素进行排序,find 用于在容器中查找指定元素。 8. C++11 的 auto 和 nullptr 是 C++11 新增的特性。auto 可以自动推导变量类型,nullptr 是空指针常量。它们可以简化代码并提高代码的可读性和可维护性。 9. C++11 的 for 范围遍历是一种更加简洁的遍历容器的方式,可以自动遍历容器中的每个元素,无需显式使用迭代器。 10. C++11 的 Lambda 表达式是一种匿名的函数对象,可以在需要函数对象的地方使用,提供了一种方便的语法来定义和使用函数对象。 11. C++11 的智能指针、右值引用和多线程是为了提供更好的内存管理和并发编程支持。智能指针用于自动管理动态分配的内存,右值引用支持移动语义和完美转发,多线程支持并发执行任务。 12. 多线程同步方式包括互斥锁、条件变量、原子操作等,用于保证多个线程之间的正确操作和协调。互斥锁用于保护共享资源,条件变量用于线程间的通信,原子操作用于保证多线程下的原子性操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值