Singleton模式线程相关的(C\C++)

简介:

这种需求的最新发展。

我需要一个静态类,无论地方,我可以在线程中调用它public功能对应的功能已经完成。

这个静态类会调用我初始化给它的一个指针,这个指针是与线程一一相应的;

准确来说这样的模式应该叫多例模式,它是单例模式和工厂模式的一个变式。

以下说一下,我的实现思路。

(一)实例指针

假设是单例模式,会有一个指针或者静态变量来存储这个静态变量。而这里多例。则须要使用一个Map来存储,Map的key是当前线程的句柄,Map定义例如以下:

typedef map<DWORD, CRelatedThreadMultiton*> ThreadMap;

(二)获取指针

与单例模式同样,构造是私有的,通过静态的接口来获得实例。而与其有所差异的地方在于,假设已经存在于map。我须要从map中拿到相应的instance,而假设不存在。则须要在new之后,将其存放于map中。

因为是线程相关的,也就是说一个线程中仅仅会有一个instance,所以它本质上与单线程的单例模式是类似的,不会存在多线程的危急。

以下是获得单例指针的代码:

	// 获得指定的单例
	CRelatedThreadMultiton *pInstance = NULL;
	if (InstanceExisted(dwThreadId))
	{
		pInstance = m_ThreadIdMap[dwThreadId];
	}
	else
	{
		pInstance = new CRelatedThreadMultiton;
		m_ThreadIdMap[dwThreadId] = pInstance;
	}
这里推断是否存在。须要通过遍历map表来实现,实现例如以下:

BOOL CRelatedThreadMultiton::InstanceExisted( DWORD _dwThreadId )
{
	ThreadMap::iterator itor = m_ThreadIdMap.begin();
	while (itor!=m_ThreadIdMap.end())
	{
		if (itor->first == _dwThreadId)
		{
			return TRUE;
		}
		itor++;
	}

	return FALSE;
}
(三)instance的释放

我觉得instance有两个释放时机,一个是我在获得一个新的之前,我能够检查map表中是否有无效的项。假设有。则擦除之。还有一个是在析构的时候须要清空map表,删除指针。

删除无效指针的实现例如以下:

// 删除map中已经失效的指针
BOOL CRelatedThreadMultiton::RemoveInvalidInstance()
{
	ThreadMap::iterator itor = m_ThreadIdMap.begin();
	while (itor!=m_ThreadIdMap.end())
	{
		if (!ThreadExisted(itor->first))
		{
			//delete itor->second;
			itor = m_ThreadIdMap.erase(itor);
		}
		else
			itor++;
	}

	return TRUE;
}
这里须要用到推断一个遍历当前进程的线程的方法,能够通过快照的方式遍历。代码不难,仅仅是须要熟悉几个经常使用的API,能够例如以下实现:

// 遍历当前进程的全部线程。推断当前进程是否存在
BOOL CRelatedThreadMultiton::ThreadExisted(DWORD _dwThreadId)
{
	BOOL bRet = FALSE;
	HANDLE hThreadSnap = INVALID_HANDLE_VALUE; 
	THREADENTRY32 threadEntry32; 

	// 创建当前进程的快照
	hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 
	if( hThreadSnap == INVALID_HANDLE_VALUE ) 
		return FALSE;

	threadEntry32.dwSize = sizeof(THREADENTRY32 ); 

	// 获得快照的第一个线程
	if( !Thread32First( hThreadSnap, &threadEntry32 ) ) 
	{
		CloseHandle( hThreadSnap );     // Must clean up the snapshot object!
		return FALSE;
	}

	// 依次遍历全部线程。检查是否存在该线程
	do 
	{ 
		if (threadEntry32.th32ThreadID == _dwThreadId)
		{
			bRet = TRUE;
			break;
		}
	} while( Thread32Next(hThreadSnap, &threadEntry32 ) ); 

	CloseHandle( hThreadSnap );		// 关闭快照

	return bRet;
}

</pre><span style="white-space:pre">		</span>(四)析构</p><p><span style="white-space:pre">		</span>事实上,本质上来说,这个线程相关的多例模式就是一个单例模式。能够全然依照单例模式自己主动析构的方法进行析构。</p><p><span style="white-space:pre">		</span>定义一个内部类。声明其相应的静态成员变量。

</p><p><pre name="code" class="cpp"> class CGarbo // 用于在析构函数中释放各个Instance句柄 { public: ~CGarbo() { RemoveInvalidInstance(); } }; static CGarbo garbo;


须要注意的是,静态的类成员变量,定义和声明是须要分开的,类内声明,类外定义,不多说,以下是map和garbo成员的定义与初始化:

// 为静态成员变量定义
ThreadMap CRelatedThreadMultiton::m_ThreadIdMap;
CRelatedThreadMultiton::CGarbo CRelatedThreadMultiton::garbo;

(五)初始化线程数据与使用线程数据

为了更方便的測试,我们定义一个类,用于模拟线程相应的数据结构,

该測试类例如以下:

typedef struct _testStruct
{
	int a;
	int b;
	int c;
}testStruct;

然后提供一个PrintC接口用于对外输出

public:
	BOOL PrintC();
BOOL CRelatedThreadMultiton::PrintC()
{
	printf("c:%d\n", m_pTest->c);

	return TRUE;
}

最后写两个线程。用于測试。我们的结果怎样:

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Multiton.h"

#include<iostream>
#include <process.h>

using namespace std;

//DWORD WINAPI SubThread1(LPVOID lpParam)
unsigned _stdcall SubThread1(void* param)
{
	testStruct test;
	test.c = 1;

	CRelatedThreadMultiton *pInstance = NULL;
	pInstance = CRelatedThreadMultiton::GetRTMultiton();
	pInstance->Init((PVOID *)&test);

	while(TRUE)
	{
		pInstance->PrintC();
		
		static int j =0;
		j++;
		if (j>10)
		{
			break;
		}
		Sleep(500);
	}

	return 0;
}

unsigned _stdcall SubThread2(void* param)
{
	testStruct test;
	test.c = 2;

	CRelatedThreadMultiton *pInstance = NULL;
	pInstance = CRelatedThreadMultiton::GetRTMultiton();
	pInstance->Init((PVOID *)&test);

	while(TRUE)
	{
		pInstance->PrintC();
		
		static int i =0;
		i++;
		if (i>10)
		{
			break;
		}
		Sleep(1000);
	}
	return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
	DWORD hProcess = GetCurrentProcessId();

	HANDLE hThread1;
	HANDLE hThread2;

	unsigned int uThreadID1;
	unsigned int uThreadID2;

	hThread1 = (HANDLE)_beginthreadex(NULL, 0, SubThread1, NULL, NULL, &uThreadID1);
	hThread2 = (HANDLE)_beginthreadex(NULL, 0, SubThread2, NULL, NULL, &uThreadID2);
	
	::WaitForSingleObject(hThread1, INFINITE);
	::WaitForSingleObject(hThread2, INFINITE);

	_endthreadex(uThreadID1);
	_endthreadex(uThreadID2);

	return 0;
}

最后,放一下打印的结果:


ok,如今已经实现了最初希望的目标,假设有不论什么建议和问题,欢迎大家斧正,谢谢!~

近期发现自己的博客居然和自己做事一般麻乱。甚是烦躁,趁着端午节假期期间,准备做个小的调整。另,须要学的东西真的好多。就拿设计模式来说,略微有些编程经验的,一两个小时也能看懂其目的和实现技术。更专家一些。甚至能够自己再独立实现。可是。工作中慢慢用来,才应了陆游的一句诗词“纸上得来终觉浅,须知此事要躬行。” 被觉得是最简单的一个单例模式,在面对多线程的时候,都须要有番考量才敢用之。

贴上project的0分下载地址:

http://download.csdn.net/detail/fukainankai/7425211

版权声明:本文博客原创文章,博客,未经同意,不得转载。






本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4755855.html,如需转载请自行联系原作者


相关文章
|
22天前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
36 1
C++ 多线程之初识多线程
|
5天前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
22天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
41 6
|
25天前
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
61 5
|
22天前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
18 0
C++ 多线程之线程管理函数
|
22天前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
16 0
Linux C/C++之线程基础
|
3月前
|
设计模式 安全 Java
|
3月前
|
Java 调度
基于C++11的线程池
基于C++11的线程池
|
2月前
|
JavaScript 安全 前端开发
ArkTS线程中通过napi创建的C++线程
需要注意的是,N-API和ArkTS的具体使用会随Node.js的版本不断更新和变化,所以在实际编写代码前,查看最新的官方文档是很重要的,以了解最新的最佳实践和使用模式。此外,C++线程的使用在Node.js插件中应当慎重,过多地使用它们可能会造成资源争用,并可能降低应用程序的性能。
51 0
|
4月前
|
算法 编译器 C++
开发与运维线程问题之在C++的原子操作中memory_order如何解决
开发与运维线程问题之在C++的原子操作中memory_order如何解决
43 2