团队网站模板,厦门人才网唯一官网登录,定西seo排名,专做特产的网站C并发编程#xff1a;使用C实现线程安全的栈
引言
在多线程编程中#xff0c;数据结构的线程安全性是至关重要的。本文将详细介绍如何使用C20标准库中的一些新特性来实现一个线程安全的栈。
什么是线程安全的栈#xff1f;
简单来说#xff0c;一个线程安全的栈是一个可…C并发编程使用C实现线程安全的栈
引言
在多线程编程中数据结构的线程安全性是至关重要的。本文将详细介绍如何使用C20标准库中的一些新特性来实现一个线程安全的栈。
什么是线程安全的栈
简单来说一个线程安全的栈是一个可以被多个线程同时访问而不会导致数据不一致或其他未定义行为的栈。
自定义异常类empty_stack
在实现线程安全的栈之前我们首先定义一个自定义异常用于表示栈为空的情况。
struct empty_stack : std::exception
{const char* what() const noexcept override{return Stack is empty!;}
};这里我们继承了std::exception类并重写了what()方法。
主体结构threadsafe_stack
然后我们定义了一个名为threadsafe_stack的模板类。
template typename T
class threadsafe_stack
{
private:std::stackT data;mutable std::mutex m;// ... 后续代码
};其中data是用于存储数据的STL栈而m是一个可变的互斥量用于在多线程环境中保护data。
入栈操作push
我们使用push方法来添加一个新元素到栈顶。
void push(T new_value) noexcept
{std::scoped_lock lk(m);data.push(std::move(new_value));
}在这里我们使用std::scoped_lock来自动管理锁的生命周期并使用std::move来进行移动语义以提高性能。
出栈操作pop
对于出栈操作我们提供了两种方式一种返回一个shared_ptr另一种将值存储在一个引用参数中。
返回shared_ptr的pop
std::shared_ptrT pop()
{std::scoped_lock lk(m);if (data.empty()) throw empty_stack();auto const res(std::make_sharedT(std::move(data.top())));data.pop();return res;
}将值存储在引用中的pop
void pop(T value)
{std::scoped_lock lk(m);if (data.empty()) throw empty_stack();value std::move(data.top());data.pop();
}在这两种情况下我们都首先检查栈是否为空并在必要时抛出自定义的empty_stack异常。
检查栈是否为空empty
此外我们还提供了一个empty方法用于检查栈是否为空。
bool empty() const noexcept
{std::scoped_lock lk(m);return data.empty();
}测试test_threadsafe_stack
最后我们通过一个简单的测试函数来演示如何使用这个线程安全的栈。
void test_threadsafe_stack()
{threadsafe_stackint s;std::thread t1([](){for (int i 0; i 10; i){s.push(i);std::cout Pushed i std::endl;}});std::thread t2([](){for (int i 0; i 10; i){try{auto val s.pop();std::cout Popped *val std::endl;}catch (const empty_stack e){std::cout Exception: e.what() std::endl;}}});t1.join();t2.join();
}总结
使用C20的新特性如std::scoped_lock我们能更方便地实现线程安全的数据结构。本文详细介绍了如何实现一个线程安全的栈并提供了完整的代码示例。希望这能帮助你更好地理解多线程编程和C20的一些新特性。