将一般函数转为线程运行

来源:互联网 发布: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(&lt0);
 mpool.AddJob(&lt1);
 mpool.AddJob(&lt2);
 mpool.AddJob(&lt3);
 mpool.AddJob(&lt4);

 Sleep(100);

 //等待所有任务结束后退出
 while (!mpool.TaskOver()) {
  Sleep(1000);
 }

}

int main(int argc, char* argv[])
{
 test();
 return 0;
}

由上面的代码可以看到,尽管 t0 到 t4的函数,每个函数的原型都不同,需要输入不同的运行参数,

但是通过模版的封装,可以统一的放入同一个线程池中运行,并且不需要建立额外的结构来传输参数,

对于将已有代码转换为线程运行,很方便,不需要编写额外的的代码,同时,如果要撤销作为线程运行也方便.

//由于水平有限,上面的实现方式是由局限性的,如对于
//函数参数为引用类型的函数是由问题的,
//所有的参数持有结构都是使用的缺省构造函数,
//对于引用类型需要显式的初始化,所以,对于
//象 void tt(int&) 类型的函数,会出现错误
//希望大家能讨论一下,看看有没有解决的方法.


//另外,boost中有的类也可以实现上述的功能,由于对boost不熟悉
//我不知道在boost中是如何解决 引用参数的问题和 多个参数的传入问题的.


//水平有限,希望大家指正.

原创粉丝点击