首页 > 编程语言 >【并发编程十四】c++原子操作(2)——实现自旋锁

【并发编程十四】c++原子操作(2)——实现自旋锁

时间:2023-03-16 16:46:41浏览次数:65  
标签:lock 编程 c++ 并发 mutex 自旋 线程 include spinlock

 

【并发编程十四】c++原子操作(2)——实现自旋锁

 

  • 简介
    在介绍完原子操作,我们这篇使用c++提供的原子操作,实现一个自旋锁,并加以利用。

原子操作参见【并发编程十三】c++原子操作

一、自旋锁简介

“自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞

  • 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

  • 自旋锁,它并不会放弃 CPU 时间片,而是通过自旋等待锁的释放,也就是说,它会不停地再次地尝试获取锁,如果失败就再次尝试,直到成功为止

  • 非自旋锁,非自旋锁和自旋锁是完全不一样的,如果它发现此时获取不到锁,它就把自己的线程切换状态,让线程休眠,然后 CPU 就可以在这段时间去做很多其他的事情,直到之前持有这把锁的线程释放了锁,于是 CPU 再把之前的线程恢复回来,让这个线程再去尝试获取这把锁。如果再次失败,就再次让线程休眠

非自旋锁和自旋锁最大的区别,就是如果它遇到拿不到锁的情况,它会把线程阻塞,直到被唤醒。而自旋锁会不停地尝试

二、使用自旋锁

#include <iostream>
#include<thread>
#include<mutex>
#include <atomic>

using namespace std;

class spinlock_mutex
{
public:
	spinlock_mutex() {};

	//spinlock_mutex(const spinlock_mutex& origin); // add this line
	~spinlock_mutex() {};

	void lock()
	{
		while (flag.test_and_set(memory_order_acquire));
	}
	void unlock()
	{
		flag.clear(memory_order_release);
	}
private:
	atomic_flag flag = ATOMIC_FLAG_INIT;
};

int g = 0;
spinlock_mutex mtx;

void task()
{
	for (int i = 0; i < 5; i++)
	{
		lock_guard<spinlock_mutex> my_lock(mtx);
		//mtx.lock();
		g++;
		cout << "task:g="<<g << endl;
		//mtx.unlock();
	}
}

int main()
{
	//cout << "g"<<g << endl;

	thread t1(task);
	thread t2(task);

	t1.join();
	t2.join();
	return 0;
}

输出

三、不使用自旋锁

#include <iostream>
#include<thread>
#include<mutex>
#include <atomic>

using namespace std;

//class spinlock_mutex
//{
//public:
//	spinlock_mutex() 	
//	{
//	}
//
//	//spinlock_mutex(const spinlock_mutex& origin); // add this line
//	~spinlock_mutex() {};
//
//	void lock()
//	{
//		while (flag.test_and_set(memory_order_acquire));
//	}
//	void unlock()
//	{
//		flag.clear(memory_order_release);
//	}
//private:
//	atomic_flag flag = ATOMIC_FLAG_INIT;
//};

int g = 0;
//spinlock_mutex mtx;

void task()
{
	for (int i = 0; i < 5; i++)
	{
		// lock_guard<spinlock_mutex> my_lock(mtx);
		//mtx.lock();
		g++;
		cout << "task:g="<<g << endl;

		//mtx.unlock();
	}
}

int main()
{
	//cout << "g"<<g << endl;

	thread t1(task);
	thread t2(task);

	t1.join();
	t2.join();
	return 0;
}

输出

四、分析

  • 因为io是进程内共享的,所以当我们操作而不加锁时,会出现输出串行的现象。(说明我们实现的自旋锁可用、有效)
  • 我们实现的自旋锁可以配合lock_guard使用;
  • 当然我们也可以直接使用mtx.lock()、mtx.unlock();进行加锁和解锁。
 

标签:lock,编程,c++,并发,mutex,自旋,线程,include,spinlock
From: https://www.cnblogs.com/lidabo/p/17223149.html

相关文章