C++并发实战17:线程安全的stack和queue(二)

2014-11-24 07:18:37 · 作者: · 浏览: 3
: threadsafe_queue(): head(new node),tail(head.get())//构造函数创建一个虚拟节点,初始时head和tail都指向这个虚拟节点,这也是判断queue为空的条件head==tail都指向同一个虚拟节点 {} threadsafe_queue(const threadsafe_queue& other)=delete; threadsafe_queue& operator=(const threadsafe_queue& other)=delete;//为了简化代码禁止拷贝和赋值 std::shared_ptr try_pop()// { std::unique_ptr old_head=pop_head(); return old_head old_head->data:std::shared_ptr (); } void push(T new_value)//向队列添加一个元素,T的实例在临界区外创建即使抛出异常queue也没有被修改,而且加速多个线程的添加操作 { std::shared_ptr new_data(std::make_shared (std::move(new_value)));//注意make_shared可以提高效率,make_shared()函数要比直接创建shared_ptr对象的方式快且高效,因为它内部仅分配一次内存,消除了shared_ptr 构造时的开销 std::unique_ptr p(new node);//创建一个虚拟节点,tail始终指向一个虚拟节点从而和head分开(队列中有元素时),防止队列中只有元素时pop和top都操作的tail和head(若没有虚拟节点此时tail和head都是同一个节点) node* const new_tail=p.get(); std::lock_guard tail_lock(tail_mutex); tail->data=new_data; tail->next=std::move(p); tail=new_tail; } }; 关于上述队列的几点说明:

1) tail->next==nullptr;tail->data==nullptr//tail始终指向一个虚拟节点
2) head==tail表示队列为空
3) head->next==tail表示队中只有一个元素
4) 队列中真实的元素x满足x!=tail, x->data指向T的实例,x->next指向下一个节点, x->next==tail表示x的队列中最后一个真实的节点

5) 采用两个mutex使得锁的粒度减小提高了并发性能


一个相对完整的线程安全queue版本:

template
  
   
class threadsafe_queue
{
  public:
    threadsafe_queue():head(new node),tail(head.get()){}
    threadsafe_queue(const threadsafe_queue& other)=delete;
    threadsafe_queue& operator=(const threadsafe_queue& other)=delete;
    std::shared_ptr
   
     try_pop() { std::unique_ptr
    
      const old_head=try_pop_head(); return old_head old_head->data:std::shared_ptr
     
      (); } bool try_pop(T& value) { std::unique_ptr
      
        const old_head=try_pop_head(value); return old_head; } std::shared_ptr
       
         wait_and_pop() { std::unique_ptr
        
          const old_head=wait_pop_head(); return old_head->data; } void wait_and_pop(T& value) { std::unique_ptr
         
           const old_head=wait_pop_head(value); } void empty() { std::lock_guard
          
            head_lock(head_mutex); return (head==get_tail()); } void push(T new_value) { std::shared_ptr
           
             new_data(std::make_shared
            
             (std::move(new_value))); std::unique_ptr
             
               p(new node); { std::lock_guard
              
                tail_lock(tail_mutex); tail->data=new_data; node* const new_tail=p.get(); tail->next=std::move(p); tail=new_tail; } data_cond.notify_one(); } private: node* get_tail() { std::lock_guard
               
                 tail_lock(tail_mutex); return tail; } std::unique_ptr
                
                  pop_head() { std::unique_ptr
                 
                   const old_head=std::move(head); head=std::move(old_head->next); return old_head; } std::unique_lock
                  
                    wait_for_data() { std::unique_lock
                   
                     head_lock(head_mutex); data_cond.wait(head_lock,[&]{return head!=get_tail();}); return std::move(head_lock); } std::unique_ptr
                    
                      wait_pop_head() { std::unique_lock
                     
                       head_lock(wait_for_data()); return pop_head(); } std::unique_ptr
                      
                        wait_pop_head(T& value) { std::unique_lock
                       
                         head_lock(wait_for_data()); value=std::move(*head->data); return pop_head(); } std::unique_ptr
                        
                          try_pop_head() { std::lock_guard
                         
                           head_lock(head_mutex); if(head.get()==get_tail()) { return std::unique_ptr
                          
                           (); } return pop_head(); } std::unique_ptr
                           
                             try_pop_head(T& value) { std::lock_guard
                            
                              head_lock(head_mutex); if(head.get()==get_tail()) { return std::unique_ptr
                             
                              (); } value=std::move(*head->data); return pop_head(); } private: struct node { s