栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

C++新特性31

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++新特性31

上两篇C++新特性29_线程同步问题的解决思路(原子操作、WindowsAPI实现原子操作、针对特定操作的WindowsAPI、如何解决同步的一般问题、 实际场景介绍解决同步问题的思路、)及C++新特性30_windows api解决线程同步(临界区、手动加EnterCriticalSection(&),LeaveCriticalSection(&)、临界区大小即颗粒度、如何自动加锁)中介绍了Windows API解决同步问题的两种方法,一种是针对特定操作的API,另一种是使用临界区的形式实现,C++11对临界区的方法进行封装之后,可以在语法上避免忘记解锁等操作。

本篇介绍如何自己利用C++封装自己实现线程同步,主要用到了2个类,一个类实现基本操作的封装,一个类利用构造和析构实现加锁和解锁的自动化。

重点: 利用引用实现在一个类中对另一个类的唯一对象的调用方法如下:

构造函数利用私有类中的CMyMutex& m_Mutex;作为参数,利用外部传入的对象g_mtx进行初始化,由于使用的是引用,保证了操作的对象指向了外部传入的对象g_mtx。

1.封装临界区方法

首先新建一个CMyMutex类对临界区方法进行封装,利用类的构造和析构将对象进行构造和析构,在类中创建加锁解锁函数。

(1)CMyMutex.h:

#pragma once
#include 

class CMyMutex
{
public:
	CMyMutex();
	~CMyMutex();
	void lock();
	void unlock();
private:
	CRITICAL_SECTION m_cs;

};

CMyMutex.cpp:

#include "CMyMutex.h"

CMyMutex::CMyMutex()
{
	//使用前,需要对该对象进行初始化
	InitializeCriticalSection(&m_cs);
}

CMyMutex::~CMyMutex()
{
	//当不在使用该锁时,需要将锁删掉
	DeleteCriticalSection(&m_cs);
}

void CMyMutex::lock()
{
	//进去加锁
	EnterCriticalSection(&m_cs);
}

void CMyMutex::unlock()
{
	//出去解锁
	LeaveCriticalSection(&m_cs);
}

(2)main()中利用封装好的类进行对象创建析构及实现加锁解锁功能:

#include 
#include 
#include 
#include 
#include 
#include "CMyMutex.h"

using namespace std;

int g_nData = 0;
// 创建临界区对象,等价于锁
CMyMutex g_mtx;

void foo() {
	//进来上锁
	g_mtx.lock();
	for (int i = 0; i < 100000; i++) {

		g_nData++;

	}
	//出去解锁
	g_mtx.unlock();
}

int _tmain(int argc, _TCHAR* argv[])
{


	std::thread t(foo);

	//进来上锁
	g_mtx.lock();
	for (int i = 0; i < 100000; i++) {
		g_nData++;
	}
	//出去解锁
	g_mtx.unlock();

	t.join();

	std::cout << g_nData << std::endl;

	return 0;
}

运行结果:

上述过程实现了临界区方法的封装,但是仍然使用的是手动的加锁和解锁功能,一旦忘记添加就会造成和上篇中忘记添加解锁造成无法跳出的问题。

2.自动实现加锁和解锁

如何实现C++语法上预防出现忘记解锁的情况出现呢?
这里利用C++中对象的构造和析构实现,创建另一个类CMyLockGuard,将加锁和解锁利用构造与析构自动进行。

(1)CMyMutex.h中创建CMyLockGuard类:

#pragma once
#include 

class CMyMutex
{
public:
	CMyMutex();
	~CMyMutex();
	void lock();
	void unlock();
private:
	CRITICAL_SECTION m_cs;

};

class CMyLockGuard 
{
public:
	//将对象的引用作为参数传递进CMyLockGuard构造中
	CMyLockGuard(CMyMutex& mtx)
		:m_Mutex(mtx)
	{
		m_Mutex.lock();
	}

	~CMyLockGuard() 
	{
		m_Mutex.unlock();
	}

private:
	//为了保证锁在使用时是唯一的,因此采用引用的形式
	CMyMutex& m_Mutex;
};

(2)CMyMutex.cpp中保持不变

(3)main中利用封装的CMyMutex类对象对CMyMutex类进行操作:

其思维导图如下:利用一个类对另一个类同一个对象操作的方法-使用引用

#include 
#include 
#include 
#include 
#include 
#include "CMyMutex.h"

using namespace std;

int g_nData = 0;
// 创建临界区对象,等价于锁
CMyMutex g_mtx;

void foo() {

	CMyLockGuard lg(g_mtx);

	for (int i = 0; i < 100000; i++) {

		g_nData++;

	}

}

int _tmain(int argc, _TCHAR* argv[])
{


	std::thread t(foo);

	CMyLockGuard lg(g_mtx);

	for (int i = 0; i < 100000; i++) {
		g_nData++;
	}


	t.join();

	std::cout << g_nData << std::endl;

	return 0;
}

(4)整个程序的思维导图:

运行结果:

3.减小颗粒度

上述程序利用构造和析构实现了自动在作用域中加锁与解锁,但是整体加锁解锁的颗粒度及作用域较大,我们可以通过使用块作用域来实现减小颗粒度的目的,代码如下:

#include 
#include 
#include 
#include 
#include 
#include "CMyMutex.h"

using namespace std;

int g_nData = 0;
// 创建临界区对象,等价于锁
CMyMutex g_mtx;

void foo() {

	{
		CMyLockGuard lg(g_mtx);

		for (int i = 0; i < 100000; i++) {

			g_nData++;

		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::thread t(foo);
	
	{
		CMyLockGuard lg(g_mtx);

		for (int i = 0; i < 100000; i++) {
			g_nData++;
		}
	}

	t.join();

	std::cout << g_nData << std::endl;

	return 0;
}

对象及局部变量的作用域指的即为包含其的最小{},当运行出作用域,就会自动释放内存资源。

4. 学习视频地址: 利用C++自己封装线程同步锁

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/751927.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号