123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- /*
- * (1)这个实现要求构建工具支持C++11的atomic mutex condition_veriable功能。这是C++11的基础特性,一般2011年以后的C++编译器都能支持。 例如,visual studio 2012以上。
- (2)这个类的实现中有两处使用了unique_lock而不是lock_guard,这是data_cond.wait所需要的,unique_lock是lock_guard的增强版。
- 通过std::move的使用(前提是我们实现的类型T定义了移动构造函数和移动赋值函数),能利用移动语义带来的性能优势。
- 使用shared_ptr<T>返回元素,用户无需释放元素的内存。
- 原文链接:https://blog.csdn.net/weixin_41855721/article/details/81703818
- 增加了一些功能函数,
- 补充了注释说明
- termination_list
- // 在退出状态下,所有的功能函数不可用,返回false或者null。
- // wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
- pop系列函数
- //(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
- //(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
- //(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
- 注注注注注意了:模板类不支持分离编译。 模板类的实现必须放在头文件
- 为了方便阅读和编程规范,依然将声明和实现分开,就像是把cpp文件的代码复制到h文件的尾部。
- 如果将实现放到cpp里面,那么就要为cpp文件加 ifndef define endif 防止重定义。
- 然后在调用方include包含cpp文件,但是这样不好。
- thread_safe_queue 就是在 Thread_safe_queue 的基础上修改的,
- * */
- #ifndef __THREAD_SAFE_LIST_H__
- #define __THREAD_SAFE_LIST_H__
- #include <list>
- #include <atomic>
- #include <mutex>
- #include <condition_variable>
- template<class T>
- class Thread_safe_list {
- public:
- Thread_safe_list();
- Thread_safe_list(const Thread_safe_list &other);
- ~Thread_safe_list();
- //(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
- //(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
- //(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
- //等待并弹出数据,成功弹出则返回true
- // 队列为空则无限等待,termination终止队列,则返回false
- bool wait_and_pop(T &value);
- //尝试弹出数据,成功弹出则返回true
- //队列为空 或者 termination终止队列,返回false
- bool try_pop(T &value);
- //等待并弹出数据,成功弹出则返回true
- // 队列为空则无限等待,termination终止队列,则返回false
- std::shared_ptr<T> wait_and_pop();
- //尝试弹出数据,成功弹出则返回true
- //队列为空 或者 termination终止队列,返回false
- std::shared_ptr<T> try_pop();
- //插入一项,并唤醒一个线程,
- //如果成功插入,则返回true, 失败则返回false
- //注:只能唤醒一个线程,防止多线程误判empty()
- bool push(T new_value);
- //清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
- bool clear();
- //清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
- bool clear_and_delete();
- public:
- //判空
- bool empty();
- //获取队列大小
- size_t size();
- //设置队列为退出状态。并唤醒所有的线程,使其通过wait
- // 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
- // wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
- void termination_list();
- //唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
- void wake_list();
- //获取退出状态
- bool get_termination_flag();
- //判断是否可以直接通过wait, m_data_list不为空或者m_termination终止时都可以通过等待。
- bool is_pass();
- public:
- std::mutex m_mutex; //队列的锁
- std::list<std::shared_ptr<T>> m_data_list; //队列数据,使用智能指针shared_ptr
- std::condition_variable m_data_cond; //条件变量
- std::atomic<bool> m_termination_flag; //终止标志位
- private:
- };
- template<class T>
- Thread_safe_list<T>::Thread_safe_list() {
- m_termination_flag = false;
- }
- template<class T>
- Thread_safe_list<T>::Thread_safe_list(const Thread_safe_list &other) {
- std::unique_lock<std::mutex> lock_this(m_mutex);
- std::unique_lock<std::mutex> lock_other(other.m_mutex);
- m_data_list = other.data_list;
- m_termination_flag = other.m_termination_flag;
- }
- template<class T>
- Thread_safe_list<T>::~Thread_safe_list() {
- //析构时,终止队列,让线程通过等待,方便线程推出。
- termination_list();
- }
- //(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
- //(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
- //(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
- //等待并弹出数据,成功弹出则返回true
- // 队列为空则无限等待,termination终止队列,则返回false
- template<class T>
- bool Thread_safe_list<T>::wait_and_pop(T &value) {
- if (m_termination_flag) {
- return false;
- } else {
- std::unique_lock<std::mutex> lk(m_mutex);
- //无限等待,一直阻塞,除非有新的数据加入或者终止队列
- m_data_cond.wait(lk, [this] { return ((!m_data_list.empty()) || m_termination_flag); });
- if (m_termination_flag) {
- return false;
- } else {
- value = std::move(*m_data_list.front());
- m_data_list.pop_front();
- return true;
- }
- }
- }
- //尝试弹出数据,成功弹出则返回true
- //队列为空 或者 termination终止队列,返回false
- template<class T>
- bool Thread_safe_list<T>::try_pop(T &value) {
- if (m_termination_flag) {
- return false;
- } else {
- std::unique_lock<std::mutex> lk(m_mutex);
- if (m_data_list.empty()) {
- return false;
- } else {
- value = std::move(*m_data_list.front());
- m_data_list.pop();
- return true;
- }
- }
- }
- //等待并弹出数据,成功弹出则返回true
- // 队列为空则无限等待,termination终止队列,则返回false
- template<class T>
- std::shared_ptr<T> Thread_safe_list<T>::wait_and_pop() {
- if (m_termination_flag) {
- return NULL;
- } else {
- std::unique_lock<std::mutex> lk(m_mutex);
- //无限等待,一直阻塞,除非有新的数据加入或者终止队列
- m_data_cond.wait(lk, [this] { return ((!m_data_list.empty()) || m_termination_flag); });
- if (m_termination_flag) {
- return NULL;
- } else {
- std::shared_ptr<T> res = m_data_list.front();
- m_data_list.pop();
- return res;
- }
- }
- }
- //尝试弹出数据,成功弹出则返回true
- //队列为空 或者 termination终止队列,返回false
- template<class T>
- std::shared_ptr<T> Thread_safe_list<T>::try_pop() {
- if (m_termination_flag) {
- return NULL;
- } else {
- std::unique_lock<std::mutex> lk(m_mutex);
- if (m_data_list.empty()) {
- return NULL;
- } else {
- std::shared_ptr<T> res = m_data_list.front();
- m_data_list.pop();
- return res;
- }
- }
- }
- //插入一项,并唤醒一个线程,
- //如果成功插入,则返回true, 失败则返回false
- //注:只能唤醒一个线程,防止多线程误判empty()
- template<class T>
- bool Thread_safe_list<T>::push(T new_value) {
- if (m_termination_flag) {
- return false;
- } else {
- std::shared_ptr<T> data(std::make_shared<T>(std::move(new_value)));
- std::unique_lock<std::mutex> lk(m_mutex);
- m_data_list.push_back(data);
- m_data_cond.notify_one();
- return true;
- }
- }
- //清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
- template<class T>
- bool Thread_safe_list<T>::clear() {
- std::unique_lock<std::mutex> lk(m_mutex);
- while (!m_data_list.empty()) {
- m_data_list.pop_front();
- }
- return true;
- }
- //清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
- template<class T>
- bool Thread_safe_list<T>::clear_and_delete() {
- std::unique_lock<std::mutex> lk(m_mutex);
- while (!m_data_list.empty()) {
- T res = NULL;
- res = std::move(*m_data_list.front());
- m_data_list.pop_front();
- if (res != NULL) {
- delete (res);
- }
- }
- return true;
- }
- //判空
- template<class T>
- bool Thread_safe_list<T>::empty() {
- std::unique_lock<std::mutex> lk(m_mutex);
- return m_data_list.empty();
- }
- //获取队列大小
- template<class T>
- size_t Thread_safe_list<T>::size() {
- std::unique_lock<std::mutex> lk(m_mutex);
- return m_data_list.size();
- }
- //设置队列为退出状态。并唤醒所有的线程,使其通过wait
- // 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
- // wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
- template<class T>
- void Thread_safe_list<T>::termination_list() {
- std::unique_lock<std::mutex> lk(m_mutex);
- m_termination_flag = true;
- m_data_cond.notify_all();
- }
- //唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
- template<class T>
- void Thread_safe_list<T>::wake_list() {
- std::unique_lock<std::mutex> lk(m_mutex);
- m_termination_flag = false;
- m_data_cond.notify_all();
- }
- //获取退出状态
- template<class T>
- bool Thread_safe_list<T>::get_termination_flag() {
- return m_termination_flag;
- }
- //判断是否可以直接通过wait, m_data_list不为空或者m_termination终止时都可以通过等待。
- template<class T>
- bool Thread_safe_list<T>::is_pass() {
- return (!m_data_list.empty() || m_termination_flag);
- }
- #endif //__THREAD_SAFE_LIST_H__
|