线程相关的单例模式(C\C++)
来源:互联网 发布:网络大电影立项新规定 编辑:程序博客网 时间:2024/05/21 06:42
最近开发有这样的需求,
我需要一个静态类,我可以在线程中的任何地方调用它的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);}elseitor++;}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,现在已经实现了最初希望的目标,如果有任何建议和问题,欢迎大家斧正,谢谢!~
最近发现自己的博客竟然和自己做事一般麻乱,甚是烦躁,趁着端午节假期期间,准备做个小的调整。另,需要学的东西真的好多,就拿设计模式来说,稍微有些编程经验的,一两个小时也能看懂其目的和实现技术,更专家一些,甚至可以自己再独立实现,但是,工作中慢慢用来,才应了陆游的一句诗词“纸上得来终觉浅,须知此事要躬行。”被认为是最简单的一个单例模式,在面对多线程的时候,都需要有番考量才敢用之。
贴上工程的0分下载地址:
http://download.csdn.net/detail/fukainankai/7425211
- 线程相关的单例模式(C\C++)
- 设计模式 - 线程安全的单例模式(C#)
- object-c 单例模式的线程安全
- 线程安全单例模式(C++)
- 线程安全单例模式(C++)
- 单例模式——C++(线程安全)
- 单例模式的设计(C++)
- C ++的单例模式
- 单例模式(C#)
- 单例模式(C#)
- 单例模式(C#)
- 单例模式(C++)
- 单例模式(C++)
- C#单例模式
- C#-单例模式
- 单例模式(C++)
- 【C++】单例模式
- [C++]单例模式
- 黑马程序员---多线程、线程间通信
- 【C语言】一道给力的题目
- 工作中用到linux命令(mac系统)
- mysql 反向查询 函数创建
- Android Service与Activity之间通信的几种方式
- 线程相关的单例模式(C\C++)
- 面向对象版表达式(十)
- Git 常用命令
- 美国科技产业的游说力量及其机制透析
- 决不随波逐流,记住15件事让你达成目标
- windows server 2008(X64)sql server 配置简介
- 黑马程序员_OC面向对象之继承和多态
- 微软帮助自带的弹出文件浏览对话框SHBrowseForFolder
- 查询所有表 表的所有列 与表相关的所有视图、存储过程、函数