将一般函数转为线程运行
来源:互联网 发布:windows版本升级 编辑:程序博客网 时间:2024/05/15 02:13
// thread_pool.cpp : Defines the entry point for the console application.
//
//command 模式是常用的设计模型,它可以保存请求并在以后需要的时候进行延时调用
//如对于window操作系统的消息处理和菜单操作均可以采用command模式
//但是,一般情况下,最终的invoker对于command的操作是同步方式的
//也就是说,invoker的所在线程会阻塞,直到command操作的函数返回
//对于一些不需要界面交互或者耦合程度较小的程序来说,也许需要对command采取
//异步的调用方式比如一个网络数据服务程序,连接侦听端口可以把一个请求连接
//作为一个command加入任务队列中,然后启动一个函数作为线程运行来处理这个连接请求
//但是,一般提供的多线程的操作接口,包括其中线程函数的形式都是有限制的
//如 由_beginthread 函数启动的线程 就需要 void(*)(void*)的原型
//对于需要将多个参数传入线程函数进行运行的情况,往往需要自己定义一个结构
//存储需要的参数,然后进行强制类型转换,方可传入线程,这种方式
//的代码重用性不强,实现不同的参数还需要定义不同的结构,比较繁琐
//这篇文章讨论的是采用loki的一些基本元素,
//将一些函数可以方便的转换为线程执行
//下面的代码在vc6.0 sp6 下测试通过
#include "stdafx.h"
#pragma warning (disable : 4786)
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
#include <functor.h>
#include <typemanip.h>
using namespace Loki;
#include <SmallObj.cpp>
namespace ext_loki
{
namespace ext_loki_private {
template <unsigned int len>
struct ParamHolderImpl {
};
template<>
struct ParamHolderImpl<1> {
template <class _tlist>
struct In {
TL::TypeAt<_tlist, 0>::Result P1;
};
};
template<>
struct ParamHolderImpl<2> {
template <class _tlist>
struct In {
TL::TypeAt<_tlist, 0>::Result P1;
TL::TypeAt<_tlist, 1>::Result P2;
};
};
}
//可以根据typelist自动生成一个结构并定义一个结构成员和typelist中的类型对应
//如:
//ParamHolder<TYPELIST_2(int,double)> lparam; 定义了一个结构 并实现了一个实例,并会有两个 int P1; double P2 的结构成员
//这里,我只定义了长度为2的typelist的实现,在具体的情况下,可以扩充需要的参数个数
template <class _tlist>
struct ParamHolder : public ext_loki_private::ParamHolderImpl< TL::Length<_tlist>::value >::template In<_tlist> {
};
}
namespace ext_loki
{
//定义线程启动调用的接口原型
struct Thread_Call_Func_ProtoType {
virtual void Run() = 0;
};
//定义可以提供线程启动调用的接口
template <unsigned int TListLength>
struct RunImpl : public Thread_Call_Func_ProtoType {
};
template <>
struct RunImpl<0> {
template<class _ret, class _tlist, class _threadmode>
struct In : public Thread_Call_Func_ProtoType, public Functor<_ret, _tlist, _threadmode>
{
//表示参数为空的函数调用,所以不需要参数传入
typedef Functor<_ret, _tlist, _threadmode> ImplBase;
typedef Functor<_ret, _tlist, _threadmode>::Impl Impl;
virtual void Run() {
ImplBase::operator ()();
}
template <class _ret>
In(_ret(*p)()) : ImplBase(p) {}
};
};
template <>
struct RunImpl<1> {
template <class _ret, class _tlist, class _threadmode>
struct In :public Thread_Call_Func_ProtoType, public Functor<_ret, _tlist, _threadmode>
{
ParamHolder<_tlist> m_Params;
typedef Functor<_ret, _tlist, _threadmode> ImplBase;
typedef Functor<_ret, _tlist, _threadmode>::Impl Impl;
virtual void Run() {
ImplBase::operator ()(m_Params.P1);
}
//模板函数,设置运行参数
template <class a1>
void SetParam(a1 p1) {
m_Params.P1 = p1;
}
template <class a1>
In(_ret (*p)(a1)) : ImplBase(p) {}
};
};
template <>
struct RunImpl<2> {
template <class _ret, class _tlist, class _threadmode>
struct In :public Thread_Call_Func_ProtoType, public Functor<_ret, _tlist, _threadmode>
{
ParamHolder<_tlist> m_Params;
typedef Functor<_ret, _tlist, _threadmode> ImplBase;
typedef Functor<_ret, _tlist, _threadmode>::Impl Impl;
virtual void Run() {
ImplBase::operator ()(m_Params.P1,m_Params.P2);
}
template <class a1, class a2>
void SetParam(a1 p1,a2 p2) {
m_Params.P1 = p1;
m_Params.P2 = p2;
}
template <class a1,class a2>
In(_ret (*p)(a1,a2)) : ImplBase(p) {}
};
};
//上面的代码可以按照实际的需要扩充参数的数量
//////////////////////////////////////////////////////////////////////////
//定义一个任务单元,可以作为函数子使用
template <class _ret, class _tlist = NullType, class _threadmode = DEFAULT_THREADING>
class Task_Unit : public RunImpl< TL::Length<_tlist>::value >::template In<_ret,_tlist,_threadmode>
{
typedef RunImpl< TL::Length<_tlist>::value >::template In<_ret,_tlist,_threadmode> ImplBase;
public:
template <class _ret>
Task_Unit(_ret (*p)()) : ImplBase(p) {}
template <class _ret,class a1>
Task_Unit(_ret(*p)(a1)) : ImplBase(p) {}
template <class _ret,class a1,class a2>
Task_Unit(_ret(*p)(a1,a2)) : ImplBase(p) {}
~Task_Unit() {}
};
//上面的代码扩充到了数量为2个参数
//对于原型为 void function_be_call(int value); 的函数可以这样调用
// Task_Unit<void,TYPELIST_1(int)> ltask(function_be_call);
// ltask.SetParam(100);
// ltask.Run();
// 或者直接调用ltask(100); 也可以
}
//上面已经实现了函数子可以自己持有运行时候需要调用的参数
//并且由了统一的调用接口Run()
//下面就定义线程运行的最终实现
//用模板方式实现了一个线程管理器,或者可以叫线程池
namespace ext_loki
{
//表示线程的状态,用于管理线程运行的状态
enum __enum_thread__state {
_at_idle = 0,
_at_assign,
_at_run,
_at_exit
};
//api实现的自定义互斥类,对于在不使用mfc的时候可以使用
class thread_mutex
{
private:
HANDLE m_Handle;
public:
BOOL Lock() {
BOOL ret = FALSE;
DWORD waitret = WaitForSingleObject(m_Handle,1000);
if (waitret == WAIT_OBJECT_0) {
ret = TRUE;
}
return ret;
}
BOOL Unlock() {
BOOL ret = FALSE;
ret = ReleaseMutex(m_Handle);
return ret;
}
public:
thread_mutex() {
m_Handle = CreateMutex(NULL,FALSE,NULL);
}
~thread_mutex() {
if (m_Handle) {
CloseHandle(m_Handle);
}
}
};
//自定义的线程锁
template <typename _locktype>
class thread_lock
{
private:
_locktype* m_pLocktype;
public:
BOOL Lock() {
return m_pLocktype->Lock();
}
BOOL Unlock() {
return m_pLocktype->Unlock();
}
public:
thread_lock(_locktype* value) : m_pLocktype(value) {}
~thread_lock(){}
};
//定义了一个数据的 holder,可以对其中的数据进行线程安全的访问
//如
//Mutex_Access<__enum_thread__state,thread_mutex,thread_lock<thread_mutex> >
//Mutex_Access<__enum_thread__state,CMutex,CSingleLock> 如果使用mfc
template <class _data,class _mutex,class _lock>
class Mutex_Access
{
private:
_mutex m_Mutex;
_data m_Value;
public:
void operator=(_data value) {
_lock lock(&m_Mutex);
lock.Lock();
m_Value = value;
lock.Unlock();
}
_data operator*() {
_data ret;
_lock lock(&m_Mutex);
lock.Lock();
ret = m_Value;
lock.Unlock();
return ret;
}
public:
Mutex_Access(){}
Mutex_Access(_data& value) {
m_Value = value;
}
~Mutex_Access(){}
};
//定义一个传入线程的统一参数结构
template <class _thread_state,class _functor>
struct thread_param {
Mutex_Access<_thread_state,thread_mutex,thread_lock<thread_mutex> > m_ThreadState;
_functor* m_pFunctor;
};
//调用最终的调用函数,调用传入的函数子
template <class actual_param>
void thread_func_impl(actual_param* param)
{
param->m_ThreadState = _at_run;
param->m_pFunctor->Run();
param->m_ThreadState = _at_exit;
}
//实现的一个线程管理器
//class _functor 指定函数子接口
//class _size 指定最大的线程数量 使用Int2Type<x> 类型,可以指定线程数量
//class _thread_begin_func 指定启动线程的函数的原型
//如window平台的 _beginthread 的原型是
//unsinged long (void(__cdecl*)(void*),unsigned,void*)
template<class _functor,class _size,class _thread_begin_func>
class thread_pool
{
public:
typedef thread_param<__enum_thread__state,_functor> ParamImpl;
typedef void (*ThreadFuncImpl)(void*);
private:
_thread_begin_func m_BeginThreadFunc; //启动线程的函数指针
ThreadFuncImpl m_pThreadFunc; //作为线程启动的函数指针
ParamImpl m_Tasks[_size::value];
public:
//添加一个任务并将其作为线程运行
BOOL AddJob(_functor* job) {
int i;
BOOL ret = FALSE;
for (i = 0; i < _size::value; i++) {
if (*m_Tasks[i].m_ThreadState == _at_idle) {
m_Tasks[i].m_ThreadState = _at_assign;
m_Tasks[i].m_pFunctor = job;
m_BeginThreadFunc(m_pThreadFunc,0,(void*)&m_Tasks[i]);
ret = TRUE;
break;
}
}
return ret;
}
//回收已经完成的任务参数,用于重新分配任务
void TaskCollect()
{
int i;
for (i = 0; i < _size::value; i++) {
if (*m_Tasks[i].m_ThreadState == _at_exit) {
m_Tasks[i].m_ThreadState = _at_idle;
}
}
}
//判断是不是所有的运行任务是不是全部结束
BOOL TaskOver()
{
BOOL ret = TRUE;
int i;
for (i = 0; i < _size::value; i++) {
if (*m_Tasks[i].m_ThreadState == _at_run || *m_Tasks[i].m_ThreadState == _at_assign) {
ret = FALSE;
break;
}
}
return ret;
}
public:
thread_pool(_thread_begin_func value,ThreadFuncImpl tf) : m_BeginThreadFunc(value), m_pThreadFunc(tf) {
int i;
for (i = 0; i < _size::value; i++) {
m_Tasks[i].m_ThreadState = _at_idle;
}
}
~thread_pool(){}
};
#define THREAD_CALL_IMPL(e) void thread_call_##e(void* param) /
{ /
typedef e::ParamImpl thread_p; /
thread_p* p = static_cast<thread_p*>(param); /
ext_loki::thread_func_impl(p); /
}
}
//下面的代码开始测试将函数作为线程运行
//从 t0 到 t4 都为测试函数
//全局互斥,防止屏幕字符输出的时候发生混乱
ext_loki::thread_mutex gmutex;
void t0()
{
int i;
for (i = 0; i < 100; i++) {
ext_loki::thread_lock<ext_loki::thread_mutex> lock(&gmutex);
lock.Lock();
cout << "t0 funtion called" << endl;
lock.Unlock();
Sleep(100);
}
}
void t1(int param)
{
int i;
for (i = 0; i < param; i++) {
ext_loki::thread_lock<ext_loki::thread_mutex> lock(&gmutex);
lock.Lock();
cout << "t1 funtion called with param " << param << endl;
lock.Unlock();
}
}
void t2(int v1,int v2)
{
int i;
for (i = 0; i < 100; i++) {
ext_loki::thread_lock<ext_loki::thread_mutex> lock(&gmutex);
lock.Lock();
cout << "t2 funtion called with param " << v1 << " " << v2 << endl;
lock.Unlock();
}
}
void t3(int v1, char c1)
{
int i;
for (i = 0; i < 100; i++) {
ext_loki::thread_lock<ext_loki::thread_mutex> lock(&gmutex);
lock.Lock();
cout << "t3 funtion called with param " << v1 << " " << c1 << endl;
lock.Unlock();
}
}
void t4(int* pint)
{
int i;
for (i = 0; i < 100; i++) {
ext_loki::thread_lock<ext_loki::thread_mutex> lock(&gmutex);
lock.Lock();
cout << "t4 funtion called with param " << *pint << endl;
lock.Unlock();
}
}
//定义个线程管理器类型,最大运行线程数量为10
typedef ext_loki::thread_pool<ext_loki::Thread_Call_Func_ProtoType,Int2Type<10>,unsigned long (*)(void(__cdecl *)( void * ),unsigned,void*)> used_thread_pool;
//用宏生成一个全局函数,作为线程启动的入口点
THREAD_CALL_IMPL(used_thread_pool)
//测试函数
void test()
{
//定义一个线程管理器
used_thread_pool mpool(_beginthread,thread_call_used_thread_pool);
//定义不同的函数子并设置参数
ext_loki::Task_Unit<void> lt0(t0);
ext_loki::Task_Unit<void, TYPELIST_1(int)> lt1(t1);
lt1.SetParam(100);
ext_loki::Task_Unit<void, TYPELIST_2(int,int)> lt2(t2);
ext_loki::Task_Unit<void, TYPELIST_2(int,char)> lt3(t3);
lt3.SetParam(111,'H');
int input = 4321;
ext_loki::Task_Unit<void, TYPELIST_1(int*)> lt4(t4);
lt4.SetParam(&input);
//开始向管理器中加入任务作为线程运行
mpool.AddJob(<0);
mpool.AddJob(<1);
mpool.AddJob(<2);
mpool.AddJob(<3);
mpool.AddJob(<4);
Sleep(100);
//等待所有任务结束后退出
while (!mpool.TaskOver()) {
Sleep(1000);
}
}
int main(int argc, char* argv[])
{
test();
return 0;
}
由上面的代码可以看到,尽管 t0 到 t4的函数,每个函数的原型都不同,需要输入不同的运行参数,
但是通过模版的封装,可以统一的放入同一个线程池中运行,并且不需要建立额外的结构来传输参数,
对于将已有代码转换为线程运行,很方便,不需要编写额外的的代码,同时,如果要撤销作为线程运行也方便.
//由于水平有限,上面的实现方式是由局限性的,如对于
//函数参数为引用类型的函数是由问题的,
//所有的参数持有结构都是使用的缺省构造函数,
//对于引用类型需要显式的初始化,所以,对于
//象 void tt(int&) 类型的函数,会出现错误
//希望大家能讨论一下,看看有没有解决的方法.
//另外,boost中有的类也可以实现上述的功能,由于对boost不熟悉
//我不知道在boost中是如何解决 引用参数的问题和 多个参数的传入问题的.
//水平有限,希望大家指正.
- 将一般函数转为线程运行
- 将字符串转为十六进制函数
- 如何将循环转为递归函数
- sql中函数将金额转为中文
- listagg函数将查询列转为行
- win7将任意程序转为系统服务运行的脚本
- 将一般三维文件转为.x文件(以solidworks导出的STL为例)
- javascript里将函数名字符串转为函数并执行
- 将中文转为unicode 及转回中文函数
- 将中文转为unicode 及转回中文函数
- 将中文转为unicode 及转回中文函数
- 用OPEN函数将XML数据转为关联数据
- 如何将符号表达式转为函数句柄[Matlab]
- 一般函数
- 一般函数
- 将DVDRip转为RMVB
- 将 bmp 转为jpg
- 将 bmp 转为jpg
- 第一个想到的是你
- java.util.zip.CRC32翻译
- 触发器,痛并快乐着~~~
- 《My SQL程序设计与数据库管理》ch1 - ch4.15学习
- 爱和责任
- 将一般函数转为线程运行
- 真正的朋友v.s.普通的朋友
- 一个人的世界与二个人的世界
- OOD设计原则
- c#中Rev和Out关键字的区别
- 成长中必须知道的20个故事
- java.util.zip.Adler32翻译
- EclipseJava
- C#调用ORACLE存储过程返回结果集及函数