文档章节

spin lock自旋锁

梦想游戏人
 梦想游戏人
发布于 2018/09/29 15:15
字数 681
阅读 82
收藏 0

自旋锁 通过cas操作,在大部分情况下可以实现比std::mutex 更高的性能

基本思想是通过原子操作去尝试获取变量的值 所有线程去竞争 该原子变量

性能:

无竞争情况下

1.spin_lock 16000W 次每秒

2.mutex 2800W次每秒

3.std::atomic<int> 24100W 次每秒

可见 自旋锁性能挺高的

5个线程竞争情况下

1.spin_lock 717W 每秒

2.mutex 509W 每秒

3.atomic<int>  5900W 每秒

高竞争情况下 还是比mutex 性能高

 

贴上代码

调整原子操作的内存顺序 可以再次加强性能,暂时用默认方式处理把

/*
Email me@dreamyouxi.com

自旋锁

*/
#pragma  once
#include <atomic>
#include <thread>
#include <chrono>

//cas 
class spin_lock
{
private:
	std::atomic<bool> _internal_tag = false;
private:
	spin_lock(const spin_lock &) = delete;
	spin_lock& operator = (const spin_lock&) = delete;
public:
	void lock();
	void unlock();
};

class spin_lock_guard
{
	spin_lock & locker;// ref
public:
	spin_lock_guard(spin_lock& lock);
	~spin_lock_guard();
};
#include "util/log.h"
#include "concurrency/spin_lock.h"
const char LOG_NAME[] = "spin_lock";
using namespace  std;

void spin_lock::lock()
{
	bool except = false;
	int times = 0;
	//fast pass
	while (true)
	{
		if (_internal_tag.compare_exchange_strong(except, true, std::memory_order_seq_cst))
		{
			//ok got it
			return;
		}
		if (++times > 4000)
		{
			//
			break;
		}
		except = false;
	}
	times = 0;
	//slow pass
	while (true)
	{
		if (_internal_tag.compare_exchange_strong(except, true, std::memory_order_seq_cst))
		{
			//ok got it
			return;
		}
		if (++times < 1000)
		{
			//
			this_thread::yield();
		}
        else
        {
           break;
        }
		except = false;
	}
	// 
	//very slow pass
	while (true)
	{
		if (_internal_tag.compare_exchange_strong(except, true, std::memory_order_seq_cst))
		{
			//ok got it
			return;
		}
		except = false;
		//内存延时 6代E5 大概是100纳秒一个周期
		//mutex 无竞争情况下 性能大概是每秒300W 次 即 0.3微秒 300纳秒
		//sleep_for 进度在win平台好像最小是1MS 因此这里的设定也许有BUG
		this_thread::sleep_for(std::chrono::nanoseconds(300));
	}
}

void  spin_lock::unlock()
{
	_internal_tag.store(false, std::memory_order_seq_cst);
}

spin_lock_guard::spin_lock_guard(spin_lock& lock) :
locker(lock)
{
	locker.lock();
}

spin_lock_guard::~spin_lock_guard()
{
	locker.unlock();
}

 

最高性能版本

/*
Email me@dreamyouxi.com

自旋锁

*/
#pragma  once
#include <atomic>
#include <thread>
#include <chrono>

//cas 
class spin_lock
{
	std::atomic_flag locker = ATOMIC_FLAG_INIT;  // NOLINT
public:
	spin_lock(const spin_lock &) = delete;
	spin_lock& operator = (const spin_lock&) = delete;

	spin_lock() = default;

	void unlock()
	{
		locker.clear(std::memory_order_release);
	}
	void lock();
private:
	bool try_lock()
	{
		bool ok = locker.test_and_set(std::memory_order_acquire);
		return !ok;
	}
};

class spin_lock_guard
{
	spin_lock & locker;// ref
public:
	spin_lock_guard(spin_lock& lock);
	~spin_lock_guard();
};



#include "util/log.h"
#include "concurrency/spin_lock.h"
const char LOG_NAME[] = "spin_lock";
using namespace  std;

void spin_lock::lock()
{
	int times = 0;
	//fast pass
	while (true)
	{
		if (try_lock())
		{
			//ok got it
			return;
		}
		if (++times > 4000)
		{
			//
			break;
		}
	}
	times = 0;
	//slow pass
	while (true)
	{
		if (try_lock())
		{
			//ok got it
			return;
		}
		if (++times < 1000)
		{
			//
			this_thread::yield();
		}
        else
        {
           break;
        }
	}
	// 
	//very slow pass
	while (true)
	{
		if (try_lock())
		{
			//ok got it
			return;
		}
		//内存延时 6代E5 大概是100纳秒一个周期
		//mutex 无竞争情况下 性能大概是每秒300W 次 即 0.3微秒 300纳秒
		//sleep_for 进度在win平台好像最小是1MS 因此这里的设定也许有BUG
		this_thread::sleep_for(std::chrono::nanoseconds(300));
	}
}

spin_lock_guard::spin_lock_guard(spin_lock& lock) :
locker(lock)
{
	locker.lock();
}

spin_lock_guard::~spin_lock_guard()
{
	locker.unlock();
}

 

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 36
博文 437
码字总数 124258
作品 0
成都
私信 提问
Linux内核自旋锁spinlock_t机制

spinlock用在什么场景? 自旋锁用在临界区代码非常少的情况。 spinlock在使用时有什么注意事项? 临界区代码应该尽可能精简 不允许睡眠(会出现死锁) Need to have interrupts disabled whe...

阿涵89
2017/12/10
0
0
Linux: spinlock and mutex

访问共享资源的代码区域称为临界区。自旋锁(spinlock)和互斥体(mutex)是保护内核临界区的两种基本机制。 自旋锁可以确保在同时只有一个线程进入临界区,其它想进入临界区的线程必须不停地原地...

长平狐
2012/06/20
360
0
原子操作、信号量、读写信号量和自旋锁

本系列文章分两部分,第一部分详细地介绍了 Linux 内核中的同步机制:原子操作、信号量、读写信号量和自旋锁的API,使用要求以及一些典型示例。第二部分将详细介绍在Linux内核中的另外一些同...

微wx笑
2015/01/30
0
0
深入浅出 Linux设备驱动并发控制介绍

在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引发"竞态",因此我们必须对共享资源进行并发控制。Linux内核中解决并发控制的最常用方...

范堡
2009/05/07
303
2
spinlock与linux内核调度的关系

作者:刘洪涛,华清远见嵌入式学院高级讲师,ARM公司授权ATC讲师。 关于自旋锁用法介绍的文章,已经有很多,但有些细节的地方点的还不够透。我这里就把我个人认为大家容易有疑问的地方拿出来...

慎思
2012/08/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL查询执行

当我们希望MySQL能够以更高的性能运行查询时,最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解了这一点,很多查询优化工作实际上就是遵循一些原则让优化器能够按照预想的合理方式...

问题终结者
46分钟前
0
0
CDH5动静态资源池配置与回滚

关于动态 静态资源池的配置以前都有提过,可以从以下几篇了解: YARN动态资源池配置案例 https://yq.aliyun.com/ziliao/346856# Hadoop YARN配置参数剖析(4)—Fair Scheduler相关参数 Hadoop...

hblt-j
51分钟前
3
0
WordPress仿站实战教程

有一个月没有写blog了,一直在学习wordpress的知识,现在能够进行简单的政府企业门户网站的仿制,wordpress的主题订制,一般是对前端要求比较高,wordpress学会了,建站还是非常的快的。下面...

临江仙卜算子
54分钟前
3
0
图像库stb_image

https://github.com/nothings/stb 目前一般主流的图像格式也就是bmp,jpg,png,tga,dds,除了DDS一般是给DX用的,虽然一堆OpenGL程序也有用的,但是我一般只用png和tga, png不用说了,带a...

robslove
今天
1
0
Spring 事务提交回滚源码解析

前言 在上篇文章 Spring 事务初始化源码分析 中分析了 Spring 事务初始化的一个过程,当初始化完成后,Spring 是如何去获取事务,当目标方法异常后,又是如何进行回滚的,又或是目标方法执行...

TSMYK
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部