spin lock自旋锁

原创
2018/09/29 15:15
阅读数 444

自旋锁 通过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();
}

 

展开阅读全文
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部