无锁队列示例泄漏内存 我试图从运行中的C++并发操作(A. Williams)中获得无锁队列示例。由于我用sinlge{0}初始化了“null”计数器_node_ptr对象,所以没有得到任何中止。但现在我仍然有依赖于未初始化值的内存泄漏和跳转。后者可能是v

无锁队列示例泄漏内存 我试图从运行中的C++并发操作(A. Williams)中获得无锁队列示例。由于我用sinlge{0}初始化了“null”计数器_node_ptr对象,所以没有得到任何中止。但现在我仍然有依赖于未初始化值的内存泄漏和跳转。后者可能是v,c++,multithreading,c++11,C++,Multithreading,C++11,无锁队列示例泄漏内存 我试图从运行中的C++并发操作(A. Williams)中获得无锁队列示例。由于我用sinlge{0}初始化了“null”计数器_node_ptr对象,所以没有得到任何中止。但现在我仍然有依赖于未初始化值的内存泄漏和跳转。后者可能是valgrind的问题,但前者对我来说是个问题,我想摆脱它。下面是完整的例子。欢迎任何帮助: // c++ -g lock_free_queue.cpp -latomic -pthread -o lock_free_queue // valg

无锁队列示例泄漏内存

我试图从运行中的C++并发操作(A. Williams)中获得无锁队列示例。由于我用sinlge{0}初始化了“null”计数器_node_ptr对象,所以没有得到任何中止。但现在我仍然有依赖于未初始化值的内存泄漏和跳转。后者可能是valgrind的问题,但前者对我来说是个问题,我想摆脱它。下面是完整的例子。欢迎任何帮助:

 // c++ -g lock_free_queue.cpp -latomic -pthread -o lock_free_queue
 // valgrind  ./lock_free_queue

#include <memory>
#include <atomic>
#include <thread>
#include <chrono>


using namespace std::chrono_literals;

// leaking memory
template<typename T>
class lock_free_queue
{
private:
  struct node;

  struct counted_node_ptr
    {
      int external_count;
      node* ptr;

      /*
      counted_node_ptr() noexcept
        : external_count(0)
        , ptr(nullptr) {}
      */
    };
  
    std::atomic<counted_node_ptr> head;
    std::atomic<counted_node_ptr> tail;

  struct node_counter
  {
    unsigned internal_count:30;
    unsigned external_counters:2;
    
    node_counter() noexcept
      : internal_count(0)
      , external_counters(2) {}
  };
  
  struct node
    {    
      std::atomic<T*> data;
      std::atomic<node_counter> count;
      std::atomic<counted_node_ptr> next;

      node() noexcept
      {
        data.store(nullptr);
        node_counter new_count;
        count.store(new_count);
        next.store(counted_node_ptr());
      }
      
      void release_ref()
      {
        node_counter old_counter=
          count.load(std::memory_order_relaxed);
        node_counter new_counter;
        do
          {
            new_counter=old_counter;
            --new_counter.internal_count;
          }
        while(!count.compare_exchange_strong
              (old_counter,new_counter,
               std::memory_order_acquire,std::memory_order_relaxed));
        if(!new_counter.internal_count &&
           !new_counter.external_counters)
          {
            delete this;
          }
      }
  };

  static void increase_external_count(
        std::atomic<counted_node_ptr>& counter,
        counted_node_ptr& old_counter)
    {
        counted_node_ptr new_counter;
        do
        {
            new_counter=old_counter;
            ++new_counter.external_count;
        }
        while(!counter.compare_exchange_strong(
                  old_counter,new_counter,
                  std::memory_order_acquire,std::memory_order_relaxed));
        old_counter.external_count=new_counter.external_count;
    }

  static void free_external_counter(counted_node_ptr &old_node_ptr)
    {
        node* const ptr=old_node_ptr.ptr;
        int const count_increase=old_node_ptr.external_count-2;
        node_counter old_counter=
            ptr->count.load(std::memory_order_relaxed);
        node_counter new_counter;
        do
        {
            new_counter=old_counter;
            --new_counter.external_counters;
            new_counter.internal_count+=count_increase;
        }
        while(!ptr->count.compare_exchange_strong(
                  old_counter,new_counter,
                  std::memory_order_acquire,std::memory_order_relaxed));
        if(!new_counter.internal_count &&
           !new_counter.external_counters)
        {
            delete ptr;
        }
    }

  void set_new_tail(counted_node_ptr &old_tail,
                      counted_node_ptr const &new_tail)
    {
        node* const current_tail_ptr=old_tail.ptr;
        while(!tail.compare_exchange_weak(old_tail,new_tail) &&
              old_tail.ptr==current_tail_ptr);
        if(old_tail.ptr==current_tail_ptr)
            free_external_counter(old_tail);
        else
            current_tail_ptr->release_ref();
    }
  
public:
    lock_free_queue()
    {
      counted_node_ptr new_head;
      new_head.ptr = new node;
      new_head.external_count = 1;
      head.store(new_head);
      tail = head.load();
    }
    lock_free_queue(const lock_free_queue& other)=delete;
    lock_free_queue& operator=(const lock_free_queue& other)=delete;
    ~lock_free_queue()
    {
      while(pop());
      delete head.load().ptr;
    }

  void push(T new_value)
    {
        std::unique_ptr<T> new_data(new T(new_value));
        counted_node_ptr new_next;
        new_next.ptr=new node;
        new_next.external_count=1;
        counted_node_ptr old_tail=tail.load();
        for(;;)
        {
            increase_external_count(tail,old_tail);
            T* old_data=nullptr;
            if(old_tail.ptr->data.compare_exchange_strong(
                   old_data,new_data.get()))
            {
              counted_node_ptr old_next{0};
              if(!old_tail.ptr->next.compare_exchange_strong
                 (old_next,new_next))
                {
                  delete new_next.ptr;
                  new_next=old_next;
                }
              set_new_tail(old_tail, new_next);
              new_data.release();
              break;
            }
            else
            {
              counted_node_ptr old_next{0};
                if(old_tail.ptr->next.compare_exchange_strong(
                       old_next,new_next))
                {
                    old_next=new_next;
                    new_next.ptr=new node;
                }
                set_new_tail(old_tail, old_next);
            }
        }
    }

  std::unique_ptr<T> pop()
    {
        counted_node_ptr old_head=head.load(std::memory_order_relaxed);
        for(;;)
        {
            increase_external_count(head,old_head);
            node* const ptr=old_head.ptr;
            if(ptr==tail.load().ptr)
            {
                return std::unique_ptr<T>();
            }
            counted_node_ptr next=ptr->next.load();
            if(head.compare_exchange_strong(old_head,next))
            {
                T* const res=ptr->data.exchange(nullptr);
                free_external_counter(old_head);
                return std::unique_ptr<T>(res);
            }
            ptr->release_ref();
        }
    }

  std::shared_ptr<T> wait_and_pop()
  {
    std::unique_ptr<T> value_ptr = pop();
    while (!value_ptr)
      {
        std::this_thread::yield();
        value_ptr = pop();
      }
    return value_ptr;
  }

};

#define MAIN
#ifdef MAIN

#include <iostream>
int main()
{
  lock_free_queue<int> hallo;
  int a = 0;
  int b = 0;
  int c = 0;
  int d = 0;
  int e = 0;
  int f = 0;


  //#define WAIT_AND_POP
#ifdef WAIT_AND_POP
  std::thread task2 =  std::thread( [&] () {
                                      //std::this_thread::sleep_for(2s);
                                      a = *(hallo.wait_and_pop());
                                      b = *(hallo.wait_and_pop());
                                    });
  std::thread task3 =  std::thread( [&] () {
                                      //std::this_thread::sleep_for(2s);g
                                      c = *(hallo.wait_and_pop());
                                      d = *(hallo.wait_and_pop());
                                    });
 
#else // #findef WAIT_AND_POP
  std::thread task2 =  std::thread( [&] () {
                                      //std::this_thread::sleep_for(2s);
                                      std::unique_ptr<int> ap = hallo.pop();
                                      a = (ap ? *(ap.get()) : 0);
                                      std::unique_ptr<int> bp = hallo.pop();
                                      b = (bp ? *(bp.get()) : 0);
                                      std::unique_ptr<int> ep = hallo.pop();
                                      e = (ep ? *(ep.get()) : 0);
                                    });
  std::thread task3 =  std::thread( [&] () {
                                      //std::this_thread::sleep_for(2s);
                                      std::unique_ptr<int> cp = hallo.pop();
                                      c = (cp ? *(cp.get()) : 0);
                                      std::unique_ptr<int> dp = hallo.pop();
                                      d = (dp ? *(dp.get()) : 0);
                                      std::unique_ptr<int> fp = hallo.pop();
                                      f = (fp ? *(fp.get()) : 0);
                                    });
#endif

  std::this_thread::sleep_for(1s);
  
  std::thread task0 =  std::thread( [&] () {
                                      hallo.push(10);
                                      hallo.push(2); 
                                    });
  
  std::thread task1 =  std::thread( [&] () {
                                      hallo.push(5);
                                      hallo.push(6); 
                                    });
  std::thread task4 =  std::thread( [&] () {
                                      hallo.push(5);
                                      hallo.push(6); 
                                    });
  task1.join();
  task2.join();
  task3.join();
  task0.join();
  task4.join();

  std::cout << "a = " << a << " b = " << b << " c = " << c << " d = " << d << std::endl;
  if (hallo.pop())
    {
      std::cout << "more data than expected" << std::endl;
    }
  else
    {
      std::cout << "ok" << std::endl;
    }
}

#endif

<代码> //C++ +G LoCuffFieldQueal.CPP-LaMat-PthO-O锁 //valgrind./lock_free_队列 #包括 #包括 #包括 #包括 使用名称空间std::chrono_文本; //内存泄漏 模板 类锁\u空闲\u队列 { 私人: 结构节点; 结构计数\u节点\u ptr { int外部_计数; 节点*ptr; /* 计数的\u节点\u ptr()无异常 :外部计数(0) ,ptr(nullptr){} */ }; 原子头; 原子尾; 结构节点计数器 { 无符号内部计数:30; 未签名的外部_计数器:2; node_counter()无异常 :内部计数(0) ,外部_计数器(2){} }; 结构节点 { 原子数据; 原子计数; std::原子下一步; node()noexcept { 数据存储(nullptr); 节点计数器新计数; 计数。存储(新计数); next.store(counted_node_ptr()); } 无效释放_ref() { 节点计数器旧计数器= 加载(标准::内存\u顺序\u松弛); 节点计数器新计数器; 做 { 新计数器=旧计数器; --新计数器。内部计数器; } 而(!count.compare\u exchange\u strong (旧柜台、新柜台、, std::内存_顺序_获取,std::内存_顺序_松弛); 如果(!新建计数器。内部计数)&& !新的\u计数器。外部\u计数器) { 删除此项; } } }; 静态空隙增加\u外部\u计数( 标准::原子和计数器, 计数(节点(ptr和旧计数器) { 计数的\u节点\u ptr新\u计数器; 做 { 新计数器=旧计数器; ++新计数器。外部计数器; } 而(!counter.compare\u exchange\u strong( 旧柜台,新柜台, std::内存_顺序_获取,std::内存_顺序_松弛); 旧计数器。外部计数器=新计数器。外部计数器; } 静态无空洞外部计数器(计数节点和旧节点) { node*const ptr=old_node_ptr.ptr; int const count\u increase=旧节点\u ptr.external\u count-2; 节点计数器旧计数器= ptr->count.load(标准::内存\u顺序\u松弛); 节点计数器新计数器; 做 { 新计数器=旧计数器; --新计数器。外部计数器; 新计数器。内部计数+=计数增加; } 而(!ptr->count.compare\u exchange\u strong( 旧柜台,新柜台, std::内存_顺序_获取,std::内存_顺序_松弛); 如果(!新建计数器。内部计数)&& !新的\u计数器。外部\u计数器) { 删除ptr; } } 无效集\新\尾(计数\节点\ ptr和旧\尾, 已计数的\u节点\u ptr常量和新\u尾部) { 节点*const current_tail_ptr=old_tail.ptr; 而(!tail.compare_exchange_弱(旧_tail,新_tail)&& 旧_tail.ptr==当前_tail_ptr); 如果(旧的\u tail.ptr==当前的\u tail\u ptr) 自由外部计数器(旧尾); 其他的 当前_tail_ptr->release_ref(); } 公众: 锁定空闲队列() { 已计数的\u节点\u ptr新\u头; new_head.ptr=新节点; 新头外部计数=1; 店面(新店面); tail=head.load(); } 锁定空闲队列(常量锁定空闲队列和其他)=删除; lock_free_queue&operator=(const lock_free_queue&other)=删除; ~lock_free_queue() { while(pop()); 删除head.load().ptr; } 无效推送(T新值) { 标准::唯一的新数据(新T(新值)); 已计数的\u节点\u ptr新\u下一步; new_next.ptr=新节点; 新的下一个。外部计数=1; 已计数的_节点_ptr old_tail=tail.load(); 对于(;;) { 增加外部尾数(尾数、旧尾数); T*old_data=nullptr; 如果(旧的\u tail.ptr->data.compare\u exchange\u strong( 旧数据,新数据。get()) { 已计数的_node _ptrold _next{0}; 如果(!old\u tail.ptr->next.compare\u exchange\u strong (旧的下一个,新的下一个) { 删除新的_next.ptr; 新的下一个=旧的下一个; } 设置新尾巴(旧尾巴,新尾巴); 新_data.release(); 打破 } 其他的 { 已计数的_node _ptrold _next{0}; 如果(旧的\u tail.ptr->next.compare\u exchange\u strong( 旧的(下一个,新的(下一个) { 旧的下一个=新的下一个; new_next.ptr=新节点; } 设置新尾翼(旧尾翼,旧尾翼下一步); } } } std::unique_ptr pop() { 计数的\u节点\u ptr old\u head=head.load(标准::内存\u顺序\u松弛); 对于(;;) { 增加外部头数(头、旧头); 节点*const ptr=old_head.ptr; if(ptr==tail.load().ptr) { 返回std::unique_ptr(); } counted_node_ptr next=ptr->next.load(); if(头。比较交换强(旧头,下一个)) { T*const res=ptr->data.exchange(空ptr); 免费外部计数器(旧头); 返回标准::唯一的ptr(res); } ptr->release_ref(); } } s
==48636== HEAP SUMMARY:
==48636==     in use at exit: 32 bytes in 1 blocks
==48636==   total heap usage: 31 allocs, 30 frees, 75,688 bytes allocated
==48636== 
==48636== Thread 1:
==48636== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==48636==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==48636==    by 0x10C75B: lock_free_queue<int>::lock_free_queue() (lock_free_queue.cpp:136)
==48636==    by 0x10A6BF: main (lock_free_queue.cpp:229)
==48636== 
==48636== LEAK SUMMARY:
==48636==    definitely lost: 32 bytes in 1 blocks
==48636==    indirectly lost: 0 bytes in 0 blocks
==48636==      possibly lost: 0 bytes in 0 blocks
==48636==    still reachable: 0 bytes in 0 blocks
==48636==         suppressed: 0 bytes in 0 blocks