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
版权声明:本文博客原创文章,博客,未经同意,不得转载。
Singleton模式线程相关的(C\C++)的更多相关文章
- (转)Spring中Singleton模式的线程安全
不知道哪里的文章,总结性还是比较好的.但是代码凌乱,有的还没有图.如果找到原文了可以进行替换! spring中的单例 spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有 ...
- 剑指Offer面试题:1.实现Singleton模式
说来惭愧,自己在毕业之前就该好好看看<剑指Offer>这本书的,但是各种原因就是没看,也因此错过了很多机会,后悔莫及.但是后悔是没用的,现在趁还有余力,把这本书好好看一遍,并通过C#通通实 ...
- 懒人模式Singleton模式Meyers版本号
直接看代码: /* Singleton模式保证:在一个程序,,一个类有且只有一个实例.并提供一个访问 它的全局访问点 在编程其中.很多情况下,需要确保有一类的一个实例 比如: windopws系统中仅 ...
- C++实现Singleton模式(effective c++ 04)
阅读effective c++ 04 (31页) 提到的singleton设计模式.了解一下. 定义: 保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享. 应用场景: 比 ...
- 剑指Offer对答如流系列 - 实现Singleton模式
目录 面试题2:实现Singleton模式 一.懒汉式写法 二.饿汉式写法 三.枚举 面试题2:实现Singleton模式 题目:设计一个类,我们只能生成该类的一个实例. 由于设计模式在面向对象程序设 ...
- 6、单例模式 Singleton模式 只有一个实例 创建型模式
1.了解Singleton模式 程序在运行时,通常都会生成很多实例.例如,表示字符串的java . lang . string类的实例与字符串是- -对- -的关系,所以当有1000个字符串的时候,会 ...
- 《剑指offer》面试题2:实现Singleton 模式
面试题2:实现Singleton 模式 题目:设计一个类,我们只能生成该类的一个实例. 只能生成一个实例的类是实现了Singleton (单例)模式的类型.由于设计模式在面向对象程序设计中起着举足 ...
- C++ Singleton模式
地址:http://www.cppblog.com/dyj057/archive/2005/09/20/346.html Singleton模式是常用的设计模式之一,但是要实现一个真正实用的设计模式却 ...
- 进程 & 线程相关知识
不管Java,C++都有进程.线程相关的内容.在这里统一整理吧. Python的线程,其实是伪线程,不能真正的并发.下面也有讲. 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序 ...
随机推荐
- Tutorial: 结合使用AngularJS和Django
好吧,我承认自己很懒,时间又不够用. 翻译的几个文章都是虎头蛇尾,但我保证这次肯定不太监. 关键的单词不翻译,实在觉得翻译成汉语很别扭,括号里是参考翻译. 有问题和建议尽管提出来,我会改进完善. Tu ...
- redis做RDB时请求超时case
近期在排查redis做rdb时会有部分请求超时的case.初步推断是我们redisserver上开启了THP(Transparent Huge Pages). 1) Linux本身的 ...
- JavaWeb 项目中的绝对路径和相对路径以及问题的解决方式
近期在做JavaWeb项目,总是出现各种的路径错误,并且发现不同情况下 / 所代表的含义不同,导致在调试路径上浪费了大量时间. 在JavaWeb项目中尽量使用绝对路径 由于使用绝对路径是绝对不会出 ...
- C#获取Excel中所有的Sheet名称
原文地址:http://blog.csdn.net/qq1010726055/article/details/6858849 Excel.Application myExcel = new Excel ...
- C# 文件操作(全部) 追加、拷贝、删除、移动文件、创建目录 修改文件名、文件夹名
原文:C# 文件操作(全部) 追加.拷贝.删除.移动文件.创建目录 修改文件名.文件夹名 本文也收集了目前最为常用的C#经典操作文件的方法,具体内容如下:C#追加.拷贝.删除.移动文件.创建目录.递归 ...
- js中点击空白区域时文本框与隐藏层的问题
当文本框获得焦点的时候,在文本框的下方显示一个浮动层. 当用户点击除了文本框和浮动层以外的网页空白处时,要隐藏浮动层. 当用户点击浮动层时,改变文本框的值. <!DOCTYPE html PUB ...
- Python的TkinterButton做为父窗口
#-*-coding:utf--*- import Tkinter,time,tkMessageBox,sys,BeBigModule class MainFrame: def __init__(se ...
- Xcode6在10.9.4上面crash解决
具体请看我的evernote 这里: 在10.9.4系统上面直接安装xcode6的beta3.和平时一样, 1.将beta3拖拽到application文件夹中. 2.等待copy完毕,执行xcode ...
- XSS漏洞的分类
XSS漏洞依照攻击利用手法的不同,有下面三种类型: 类型A,本地利用漏洞,这样的漏洞存在于页面中client脚本自身.其攻击步骤例如以下所看到的: Alice给Bob发送一个恶意构造了Web的URL. ...
- C#获取设备的IP和Mac类
/// <summary> /// 此类用于获得设备的Ip和Mac /// </summary> public class Mac { [DllImport("Iph ...