C++无锁编程-单链表

无锁编程单链表的实现,主要特性如下:

  • 只能从尾部追加元素
  • 不支持删除元素
  • 支持Iterator遍历元素
  • 提供了多线程情况下的测试用例

适用的场景如下:

  • 搜索引擎,实时索引中的倒排链表
  • 只添加元素,不删除元素的多线程场景

代码如下:

#include 
#include 
#include 
#include 
template
class LockFreeSignleLinkedList {
public:
    struct Node {
        union Data {
            DataType *ptr;
            uint64_t value;
        } data;
        std::atomic next = nullptr;
    };

    class Iterator {
    public:
        Iterator operator ++(int) {
            Iterator it;
            it.ptr = ptr->next;
            return it;
        }

        Iterator& operator ++() {
            ptr = ptr->next;
            return *this;
        }

        bool operator ==(Iterator& iter) {
            return (ptr == iter.ptr);
        }

        Iterator& operator =(const Iterator& iter) {
            ptr = iter->ptr;
            return *this;
        }

        DataType& operator *() {
            if (std::is_class::value) {
               return *(ptr->data.ptr);
            } 
            uint64_t* data_ptr = &(ptr->data.value);
            DataType* ptr = reinterpret_cast(data_ptr);
            return *ptr;
        }

        friend class LockFreeSignleLinkedList;
    private:
       Node* ptr = nullptr;
    };

    LockFreeSignleLinkedList() {
        head = new Node;
        tail = head;
    }

    void push_back(const DataType& data) {
        push_back(&data);
    }

    void push_back(const DataType* ptr) {
        Node *tmp = new Node;
        if (std::is_class::value) {
            tmp->data.ptr = const_cast(ptr);
        } else {
            DataType* tmp_ptr = reinterpret_cast(&(tmp->data.value));
            *tmp_ptr = *ptr;
        }
        for(;;) {
            ajustTail();
            Node *real_tail = tail.load(std::memory_order_relaxed);
            auto& next = real_tail->next;
            Node *real_next = next.load(std::memory_order_relaxed);
            if (nullptr != real_next) {
                continue;
            }
            if (!next.compare_exchange_weak(real_next, tmp, std::memory_order_relaxed)) {
                continue;
            } else {
                break;
            }
        }
        cnt.fetch_add(1, std::memory_order_relaxed);
        ajustTail();
    }

    Iterator begin() {
        Iterator it;
        it.ptr = head->next;
        return it;
    }

    Iterator end() {
        static Iterator blank_it;
        return blank_it;
    }

    size_t size() { return cnt.load(std::memory_order_relaxed); }

private:
    void ajustTail() {
        for(;;) {
            Node *real_tail = tail.load(std::memory_order_relaxed);
            auto& next = real_tail->next;
            Node *real_next = next.load(std::memory_order_relaxed);
            if (nullptr == real_next) {
                return;
            }
            if (!tail.compare_exchange_weak(real_tail, real_next, std::memory_order_relaxed)) {
                continue;
            }
        } // end for
    }

    Node* head = nullptr;
    std::atomic tail = nullptr;
    std::atomic cnt = 0;
};

int main()
{
    LockFreeSignleLinkedList l;
    l.push_back(9);
    l.push_back(2);
    l.push_back(4);
    l.push_back(5);
    std::cout << "list:" << std::endl;
    for (const int32_t n : l) {
        std::cout << n << std::endl;
    }
    std::cout << "retry to list:" << std::endl;
    for (auto it = l.begin(); it != l.end(); ++it ) {
        std::cout << *it << std::endl;
    }

    LockFreeSignleLinkedList l2;
    volatile bool run = false;
    auto fun = [&]() {
        for (;;) {
            if (!run) {
                continue;
            } else {
                break;
            }
        }
        std::cout<< "start pid:" << std::this_thread::get_id() << std::endl;
        for (int32_t i = 0; i < 900000; ++i) {
            l2.push_back(i);
        }    
        std::cout<< "end pid:" << std::this_thread::get_id() << std::endl;
    };

    std::thread t1([&](){fun();});
    std::thread t2([&](){fun();});
    std::thread t3([&](){fun();});
    std::thread t4([&](){fun();});
    std::atomic_thread_fence(std::memory_order_seq_cst);
    run = true;
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    size_t s1 = 0;
    for (auto it = l2.begin(); it != l2.end(); ++it ) {
       ++s1;
    }
    std::cout << "s1:" << s1 << std::endl;
    std::cout << "s2:" << l2.size() << std::endl;

    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注