第七章lock_义齿
8731 ワード
queueに関連する2つの操作がhead tailポインタに対応するため、以前の参照カウントを使用してstackを実装したのとは異なります.
だから簡単に前の技術を使ってlockを設計すればfreeアルゴリズムは適切ではありません.このような状況が発生する可能性があります.
tailポインタが指向するノードを離れた後、他のスレッドはこのノードを解放したが、headポインタはまだこのノードにアクセスしていないので、後でpopを呼び出す人がいたら.そうすれば
だから1つの__を設定すべきですm_external_count
これは_Nodeノードでは2に初期化され、tail headがアクセスしたときにのみ減算され、それぞれ対応する関数_free_external_count
具体的に理解するには、本章のstackの実现を読んでください.あなたは私の意味を理解することができます(以上は本人の心得で、同じ初心者で、理解にずれがあるかもしれませんが、具体的な読者はこの本の内容を参考にすることができます.
質問があればメールアドレスもご利用いただけます[email protected])
だから簡単に前の技術を使ってlockを設計すればfreeアルゴリズムは適切ではありません.このような状況が発生する可能性があります.
tailポインタが指向するノードを離れた後、他のスレッドはこのノードを解放したが、headポインタはまだこのノードにアクセスしていないので、後でpopを呼び出す人がいたら.そうすれば
だから1つの__を設定すべきですm_external_count
これは_Nodeノードでは2に初期化され、tail headがアクセスしたときにのみ減算され、それぞれ対応する関数_free_external_count
具体的に理解するには、本章のstackの実现を読んでください.あなたは私の意味を理解することができます(以上は本人の心得で、同じ初心者で、理解にずれがあるかもしれませんが、具体的な読者はこの本の内容を参考にすることができます.
質問があればメールアドレスもご利用いただけます[email protected])
#include <iostream>
#include <atomic>
#include <memory>
#include <thread>
#include <future>
#if defined _DEBUG
#include <crtdbg.h>
#define __MEMORY__LEAK__CHECK__ _CrtSetDbgFlag( \
_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | \
_CRTDBG_LEAK_CHECK_DF);
#define __leak__check__ __MEMORY__LEAK__CHECK__
#endif
namespace stc{
template <typename _Ty>
struct __node;
template <typename _Ty>
struct __count_node{
typedef typename __node<_Ty>* __node_pointer;
int __m_external_count;
__node_pointer __m_src;
/**data member*/
/**the consructor*/
__count_node() :__m_external_count(0),
__m_src(NULL){}
};
/**
* stack , queue head tail
* , :
* tail , , head ,
* , pop。 undefined behavior
* __m_external_count
* __node 2, tail head , __free_external_count
* , stack ,
*/
struct __inside_counter{
int __m_internal_count : 30;
unsigned int __m_external_count : 2;
};/**the inside counter */
template <typename _Ty>
struct __node{
typedef _Ty* __pointer;
typedef _Ty& __reference;
typedef typename std::atomic<__pointer> __atomic_data_type;
typedef typename std::atomic<__count_node<_Ty>> __atomic_link_type;
typedef typename std::atomic<__inside_counter> __atomic_count_type;
__atomic_data_type __m_data;
__atomic_count_type __m_counter;
__atomic_link_type __m_next;
__node() :__m_data(NULL){
__inside_counter __counter_init;
__counter_init.__m_external_count = 2;
__counter_init.__m_internal_count = 0;
__m_counter.store(__counter_init, std::memory_order_release);
}
void __release_reference();
};
template <typename _Ty>
void __node<_Ty>::__release_reference(){
__inside_counter __o_count = __m_counter.load(std::memory_order_relaxed);
__inside_counter __n_count;
do{
__n_count = __o_count;
--__n_count.__m_internal_count;
} while (!__m_counter.compare_exchange_strong(__o_count, __n_count,
std::memory_order_acquire, std::memory_order_relaxed));
if (!__n_count.__m_external_count &&
!__n_count.__m_internal_count){
delete this;
}
}
template <typename _Ty>
class lk_free_que_s{
typedef typename __count_node<_Ty> __count_node_type;
typedef typename std::atomic<__count_node_type> __atomic_count_node_type;
public:
lk_free_que_s();
~lk_free_que_s();
std::unique_ptr<_Ty> pop();
void push(const _Ty&);
private:
static void __increase_external_count(__atomic_count_node_type&, __count_node_type&);
static void __free_external_count(__count_node_type&);
void __set_tail(__count_node_type&, __count_node_type);
void __init();
void __destroy();
void __clear();
void __reset();
__count_node_type __allocate_count_node();
private:
__atomic_count_node_type __m_head;
__atomic_count_node_type __m_tail;
};
template <typename _Ty>
lk_free_que_s<_Ty>::lk_free_que_s(){
this->__init();
}
template <typename _Ty>
lk_free_que_s<_Ty>::~lk_free_que_s(){
this->__destroy();
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__init(){
__count_node_type nil = __allocate_count_node();
try{
__m_head.store(nil, std::memory_order_release);
__m_tail.store(nil, std::memory_order_release);
}catch (...){
delete nil.__m_src;
throw;
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__destroy(){
try{
while (pop());
delete __m_tail.load().__m_src;
} catch (...){}
}
template <typename _Ty>
typename lk_free_que_s<_Ty>::__count_node_type
lk_free_que_s<_Ty>::__allocate_count_node(){
try{
std::unique_ptr<__node<_Ty>> __src(new __node<_Ty>);
__count_node_type __res;
__res.__m_external_count = 1;
__res.__m_src = __src.get();
__src.release();
return __res;
}
catch (...){ throw; }
}
/**
*
*/
template <typename _Ty>
void lk_free_que_s<_Ty>::__increase_external_count(
__atomic_count_node_type& __head, __count_node_type& __o_counter){
__count_node_type __n_counter;
do{
__n_counter = __o_counter;
++__n_counter.__m_external_count;
} while (!__head.compare_exchange_strong(__o_counter,__n_counter,
std::memory_order_acquire,std::memory_order_relaxed));
__o_counter.__m_external_count = __n_counter.__m_external_count;
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__free_external_count(__count_node_type& __o_counter){
__node<_Ty>* __src = __o_counter.__m_src;
assert(__src != NULL);
const int __count_result = __o_counter.__m_external_count - 2;
__inside_counter __o_inside_counter = __src->__m_counter.load(std::memory_order_relaxed);
__inside_counter __n_inside_counter;
do{
__n_inside_counter = __o_inside_counter;
--__n_inside_counter.__m_external_count;
__n_inside_counter.__m_internal_count += __count_result;
} while (!__src->__m_counter.compare_exchange_strong(__o_inside_counter,__n_inside_counter,
std::memory_order_acquire,std::memory_order_relaxed));
if (!__n_inside_counter.__m_external_count &&
!__n_inside_counter.__m_internal_count){
delete __src;
}
}
template <typename _Ty>
std::unique_ptr<_Ty> lk_free_que_s<_Ty>::pop(){
__count_node_type __o_head = __m_head.load(std::memory_order_relaxed);//
while (true){//increase count reference
__increase_external_count(__m_head, __o_head);
__node<_Ty>* __src = __o_head.__m_src;
if (__src == __m_tail.load().__m_src){// __m_head __m_tail
__src->__release_reference();//decrease count reference
return std::unique_ptr<_Ty>();//return null pointer
}
__count_node_type __next = __src->__m_next.load();//get the next node
if (__m_head.compare_exchange_strong(__o_head, __next)){//if the head is't changed than the value of head will be the next node
std::unique_ptr<_Ty> __res(__src->__m_data.exchange(NULL));
__free_external_count(__o_head);//decrease count reference
return __res;//return the result
}
__src->__release_reference();//decrease count reference
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::push(const _Ty& __data){
std::unique_ptr<_Ty> __src(new _Ty(__data));
_Ty* __o_data = NULL;
__count_node_type __n_next = __allocate_count_node();//
__count_node_type __o_tail = __m_tail.load();//
while (true){
__increase_external_count(__m_tail, __o_tail);
__o_data = NULL;// , __m_tail
if (__o_tail.__m_src->__m_data.compare_exchange_strong(__o_data, __src.get())){
__count_node_type __o_next;//
// next __count_node_type object
if (!__o_tail.__m_src->__m_next.compare_exchange_strong(__o_next, __n_next)){
delete __n_next.__m_src;// __m_tail, __node
__n_next = __o_next;//
}
__set_tail(__o_tail, __n_next);// , __free_external_count
__src.release();// __release_reference
return;// ,
}else{// ,
__count_node_type __o_next;
if (__o_tail.__m_src->__m_next.compare_exchange_strong(__o_next, __n_next)){
__o_next = __n_next;//
__n_next.__m_src = new __node<_Ty>;// __n_next __data push
}// , __m_src
__set_tail(__o_tail, __o_next);
}
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__set_tail(__count_node_type& __o_tail, __count_node_type __next){
__node<_Ty>* __src = __o_tail.__m_src;// __src
__m_tail.compare_exchange_strong(__o_tail, __next);// , __free_external_count
if (__o_tail.__m_src == __src)// __release_reference
__free_external_count(__o_tail);
else __src->__release_reference();
}
}