无锁队列示例泄漏内存 我试图从运行中的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