Boost Lockfree

Boost Lockfree

flyfish 2014-9-30

为了最大限度的挖掘并行编程的性能考虑使用与锁无关的数据结构来编程

与锁无关的数据结构不是依赖于锁和互斥来确保线程安全。

Lockfree的重要操作就是CAS(Compare And Set)原子操作

原子操作就是多个线程访问同一个资源时,有且仅有唯一 一个线程对该资源进行操作

BOOST中的宏定义

BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B

BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B

cmpxchg:比较并交换,也就是

伪代码

bool CAS(int* p,int nOld,int nNew)
{
	bool bRet=false;
	if (*p == nOld)
	{
		*p=nNew;
		bRet=true;
	}

	return bRet;
}

CAS操作产生的ABA问题

两个线程P1和P2

P1读变量A

P1中断,

P2开始运行,读变量A,更改为B,又更改为A,

P2执行完

P1继续操作,A还是A,P1认为什么也没有发生

例如

栈 (Stack)是一种后进先出(last in first off,LIFO)的数据结构,只允许在栈顶操作。

假设有一个栈,有三个元素

A

B

C

线程P1,P2对该栈进行操作

P1 读栈顶A

P1 中断

P2 开始运行,A出栈,B出栈,A压栈(删除B)

P1 继续执行,A还是A

P1认为该栈的结构还是ABC,而此时栈里只有两个元素

就像小时候在家偷看电视,防止电视过热被父母发现,看一会儿就关上,等会儿再看。

当听见开门的声音时,以迅雷不及掩耳之势,换回开始的频道,调回音量图标的格数,关上电视,放回遥控器原来的位置并注意遥控器的朝向来表明没有看电视。

64位平台的处理方案

看boost::lockfree::detail::tagged_ptr代码

解决方式1

文件tagged_ptr_dcas.hpp

简化代码

template <class T>
class  tagged_ptr
{
public:
    typedef std::size_t tag_t;
protected:
    T * ptr;
    tag_t tag;
};

ABA问题解决方式是一个std::size_t类型的tag+指针,但不是所有平台都支持。

解决方式2

文件tagged_ptr_ptrcompression.hpp

简化代码

#if defined (__x86_64__) || defined (_M_X64)
class tagged_ptr
{
    typedef boost::uint64_t compressed_ptr_t;

public:
    typedef boost::uint16_t tag_t;

private:
    union cast_unit
    {
        compressed_ptr_t value;
        tag_t tag[4];
    };

    static const int tag_index = 3;
    static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1;
......
}

#else
#error unsupported platform
#endif

早期X86-64处理器不支持cmpxchg16b指令

在X86-64平台上,48位是地址,剩下的16位是ABA预防tag

代码

static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1;

0xffffffffffff二进制就是48个1。

tag就像一个版本号,通过tag,线程可以知道操作的数据已经发生了变化。

时间: 2024-09-18 01:31:52

Boost Lockfree的相关文章

boost::lockfree::queue多线程读写实例

最近的任务是写一个多线程的东西,就得接触多线程队列了,我反正是没学过分布式的,代码全凭感觉写出来的,不过运气好,代码能够work= = 话不多说,直接给代码吧,一个多消费者,多生产者的模式.假设我的任务是求队列的中位数是啥,每消费10000次的时候,我要知道中位数是什么. 至于加不加锁,这个看你了,我反正是加了,代码里面没写--我反正是把写的代码单独封装了一个函数,然后加了个锁 欢迎交流,这个代码已经在实际任务上面上线了,希望不会有bug. 用的是boost::lockfree::queue,官

Boost lockfree deque 生产者与消费者多对多线程应用

boost库中有一个boost::lockfree::queue类型的 队列,对于一般的需要队列的程序,其效率都算不错的了,下面使用一个用例来说明. 程序是一个典型的生产者与消费者的关系,都可以使用多线程,其效率要比使用上层的互斥锁要快很多,因为它直接使用底层的原子操作来进行同步数据的. freedeque.h 1 #pragma once#ifndef INCLUDED_UTILS_LFRINGQUEUE 2 #define INCLUDED_UTILS_LFRINGQUEUE 3 4 #de

C++ boost库无锁队列多线程并行测试与编译方法

阅读了网络中关于Boost库无锁队列的源代码,但却缺少编译方法.经过测试,确定了ubuntu 14.04中编译boost库的方法,特做记录. 无锁(free-lock)是实现高性能多线程并发编程的重要技术. 作为C++11 STL参考实现的boost库,不仅支持11标准,而且做了许多扩展,掌握其使用方法,对于提高代码质量,尤其重要. 以其多线程并行无锁队列为例,结合代码和说明,演示了无锁boost库的使用和编译方法. 代码及说明如下: //source: boost_queue.cpp //目的

boost 无锁队列

一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久违的Boost.Lockfree模块,本着学习的心态,将其翻译如下.(原文地址:http://www.boost.org/doc/libs/1_53_0/doc/html/lockfree.html) Chapter 17. Boost.Lockfree 第17章.Boost.Lockfree Ta

躲不开的多线程

Background 先来看一段程序. 线程1ready = false; init(p); ready = true; 线程2 if (ready) { p.bar(); } 线程2当ready为true时才会访问p,而在线程1里如果ready为true的话表示p已经初始化好了,看起来肯定没问题的,可是对于cpu来说这段代码几乎是不能正确执行的,这里的关键在于内存可见性(visibility)和指令重排(reordering).在SMP架构下,每一个核都有自己的cache(一般是L1和L2),

项目中的Libevent(多线程)

多线程版Libevent //保存线程的结构体 struct LibeventThread { LibEvtServer* that; //用作传参 std::shared_ptr<std::thread> spThread; // 线程 struct event_base * thread_base; // 事件根基 struct event notify_event; evutil_socket_t notfiy_recv_fd; // socketpair 接收端fd(工作线程接收通知)

zz A list of open source C++ libraries

A list of open source C++ libraries < cpp‎ | links http://en.cppreference.com/w/cpp/links/libs The objective of this page is to build a comprehensive list of open source C++ libraries, so that when one needs an implementation of particular functional

客户端,服务器发包走向

多线程模式 其实这个早看过了,在复习一下 主线程创建四个子线程,一个线程一个event_base,专门派发这个 有个监听线程,在监听线程收到连接之后轮询选择一个线程就交给他处理了,其实就这么简单 在看看包走向 客户端发过来的 加入以登录为例(不知客户端是不是走这一套) 1.先打包成protocol形式 2.在livevent里面有个100k的m_sendbuff,然后将这个protocol数据再封装一下就是前面加4个字节的数据的整个长度,然后就是调用bufferent_write 3.服务器响应

evpp设计细节系列(1):利用 enable_shared_from_this 实现一个自管理的定时器

0. 前言 https://github.com/Qihoo360/evpp是一个高性能的Reactor模式的现代化的C++11版本的高性能网络库.该项目中有一个InvokeTimer对象,接口头文件详细代码请参见https://github.com/Qihoo360/evpp/blob/master/evpp/invoke_timer.h.它是一个能自我管理的定时器类,可以将一个仿函数绑定到该定时器上,然后让该定时器自己管理并在预期的一段时间后执行该仿函数. 现在我们复盘一下这个功能的实现细节