文档章节

spin lock自旋锁

梦想游戏人
 梦想游戏人
发布于 09/29 15:15
字数 681
阅读 81
收藏 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
博文 433
码字总数 123507
作品 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
336
0
原子操作、信号量、读写信号量和自旋锁

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

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

  semainit (struct semaphore *sem, 1);   void initMUTEX_LOCKED (struct semaphore *sem);   该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,等同于   semainit (s...

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

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

慎思
2012/08/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

php获取客户端IP

php获取客户端IP 首先先阅读关于IP真实性安全的文章:如何正確的取得使用者 IP? 「任何從客戶端取得的資料都是不可信任的!」 HTTP_CLIENT_IP头是有的,但未成标准,不一定服务器都实现。 ...

DrChenXX
12分钟前
0
0
. The valid characters are defined in RFC 7230 and RFC 问题

通过这里的回答,我们可以知道: Tomcat在 7.0.73, 8.0.39, 8.5.7 版本后,添加了对于http头的验证。 具体来说,就是添加了些规则去限制HTTP头的规范性 参考这里 具体来说: org.apache.tom...

west_coast
30分钟前
1
0
刷leetcode第704题-二分查找

今天双十一买的算法书到货了,路上刷到有人说的这个题,借(chao)鉴(xi)一下别人的思路,这个是C++标准库里面的经典方法,思路精巧,优雅好品味 int search(int* nums, int numsSize, in...

锟斤拷烫烫烫
55分钟前
1
0
【分享实录】BANCOR算法详解及代码实现

1 活动基本信息 1)主题:【区块链技术工坊22期】BANCOR算法详解及代码实现 2)议题: BANCOR算法的特点和优劣势 BANCOR算法和举例 如何加入BANCOR.NETWORK交易所 如何开发自己的BANCOR去中心...

HiBlock
今天
2
0
微信小程序(2)

开始看微信小程序的教程了。刚刚看完官方教程的视图层部分。这里摘录一些自己认为的部分关键点。 1.直接修改数值无法重新渲染,需要使用setData()方法; 2.列表渲染中:wx:key用于保持项目在...

MKjy
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部