[并发并行]_[中级]_[C++实现synchronized方式的对象锁2.0]

场景

  1. 在前面的文章说过C++实现synchronized方式的对象锁[1]可以实现Javasynchronized易用特性。这个第一版的例子并没有说明如何删除pthread_mutex_t对象,随着加锁的对象增加会出现内存泄漏的情况,怎么解决?

说明

  1. C++11提供了可复制的共享的指针std::shared_ptr, 利用这个指针我们可以判断mutex有没有被其他线程使用,从而释放mutex

  2. 改进版的例子使用C++11<mutex>库来创建互斥量,不使用pthread, 读者可以自己写一个类来封装pthread_mutex_t来替换<mutex>

  3. gBASMapMutex全局锁用来获取对象锁,因为全局锁保护的代码区执行很快,所以它的时间可以忽略。主要还是业务逻辑的对象锁。

void BASLock::GLock(void* object)
{
	gBASMapMutex.lock();
	shared_ptr<void> lock;
	if(gLockObject.find(object) != gLockObject.end()){
		lock = gLockObject[object];
	}else{
		auto spMutex = make_shared<std::mutex>();
		gLockObject[object] = spMutex;
		lock = spMutex;
	}
	gBASMapMutex.unlock();
	
	auto one = (std::mutex*)lock.get();
	one->lock();
}
  1. 锁代码块可以利用C++的对象生命周期特性, 像以下方式使用,只要方法结束就会解锁。或者利用更加弹性的BASLock::GLock来加锁。
static void doSynchronizedWork()
{
	BASLock lock(&mKey);
	...
}

例子

bas_lock.h


#ifndef __BAS_LOCK_H
#define __BAS_LOCK_H

class BASLock
{
public:
	BASLock(void* object);
	~BASLock();

	static void GLock(void* object);
	static void GUnLock(void* object);
	
public:
	static int MutexSize();

private:
	void* lock_object_;
};

#endif

bas_lock.cpp


#include "bas_lock.h"
#include <map>
#include <memory>
#include <mutex>
#include <iostream>

using namespace std;

static std::map<void*,shared_ptr<std::mutex>> gLockObject;
static std::mutex gBASMapMutex;

int BASLock::MutexSize()
{
	return gLockObject.size();
}

BASLock::BASLock(void* object)
{
	lock_object_ = object;
	GLock(object);
}

BASLock::~BASLock()
{
	GUnLock(lock_object_);
}

void BASLock::GLock(void* object)
{
	gBASMapMutex.lock();
	shared_ptr<void> lock;
	if(gLockObject.find(object) != gLockObject.end()){
		lock = gLockObject[object];
	}else{
		auto spMutex = make_shared<std::mutex>();
		gLockObject[object] = spMutex;
		lock = spMutex;
	}
	gBASMapMutex.unlock();
	
	auto one = (std::mutex*)lock.get();
	one->lock();
}

void BASLock::GUnLock(void* object) 
{
	gBASMapMutex.lock();
	auto lock = gLockObject[object];
	if (lock.use_count() == 2) // 当前计数为2个时: 局部变量lock 和 gLockObject里的两个。
		gLockObject.erase(gLockObject.find(object));
	
	gBASMapMutex.unlock();

	auto one = (std::mutex*)lock.get();
	one->unlock();
}

test-synchronized

#include <iostream>
#include "bas_lock.h"
#include <thread>

using namespace std;

static int64_t mKey = 0;
static int64_t mValue = 0;
static const int gTextThreadNum = 10;

static void doSynchronizedWork()
{
	
	cout << "thread id: " << std::this_thread::get_id() << endl;
	BASLock lock(&mKey);
	for (auto i = 0; i < 1000000; i++) 
		mKey++;
	
	cout << "mKey: " << mKey << endl;
}

static void doNoSynchronizedWork()
{

	cout << "thread id: " << std::this_thread::get_id() << endl;
	for (auto i = 0; i < 1000000; i++)
		mValue++;

	cout << "mValue: " << mValue << endl;
}

int main(int argc, char const *argv[]){
    cout << "hello" << endl;

	std::thread threads[gTextThreadNum];

	// synchronized
	cout << "---- synchronized ----" << endl;
	for (auto i = 0; i < gTextThreadNum; ++i)
		threads[i] = move(std::thread(doSynchronizedWork));

	for (auto i = 0; i < gTextThreadNum; ++i)
		threads[i].join();

	cout << "mutex size: " << BASLock::MutexSize() << endl;

	// no synchronized
	cout << "---- no synchronized ----" << endl;
	for (auto i = 0; i < gTextThreadNum; ++i)
		threads[i] = move(std::thread(doNoSynchronizedWork));

	for (auto i = 0; i < gTextThreadNum; ++i)
		threads[i].join();

    system("pause");
    return 0;
}

输出

hello
---- synchronized ----
thread id: 10084thread id: 21516
thread id: 24956
thread id: 7344thread id: 8120

thread id: 3292
thread id: 23244thread id:
thread id: 10452
2148
thread id: 10812

mKey: 1000000
mKey: 2000000
mKey: 3000000
mKey: 4000000
mKey: 5000000
mKey: 6000000
mKey: 7000000
mKey: 8000000
mKey: 9000000
mKey: 10000000
mutex size: 0
---- no synchronized ----
thread id: 3632
thread id: 18928thread id: thread id: 24032thread id: 22196thread id: 14028
thread id: 8180

12936
thread id: 18080
thread id: 21480

mValue: 586629

mValue: 625623
thread id: 22556
mValue: 1300269
mValue: 1530590
mValue: 1562043
mValue: 1615115
mValue: 1810808
mValue: 1924919
mValue: 2055872
mValue: 2090888

参考

  1. C++实现synchronized方式的对象锁1.0

  2. std::thread - cppreference.com

  3. std::mutex - cppreference.com

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值