一个人的战争(2) : 成员函数与线程

         本来今天打算贴BT Client的Tracker Requester的代码的,可是整理的不太完善,因为里面牵扯到很多线程和IOCP的东西,所以我先把一部分自己封装的线程代码贴上来供各位读者评论

       先看下我对Win32线程的最浅封装,

       注意这个是声明在thrad/win32/data_type.h下的


struct  ThreadHandle                   // 这个控制线程的句柄,ID等,提供这么各类主要是为了跨平台的考虑(并不成熟)
{
        HANDLE            m_hdl;
        t_u_int32        m_tid;
        
bool            m_is_suspend;
}
;

struct  ThreadAttr                   // 属性类
{
        t_u_int32        stack_size;
        t_u_int32        priority;
        t_u_int32        create_flags;
public:
        ThreadAttr() : stack_size(
0), priority(0), create_flags(0{ }
}
;


typedef unsigned 
int  (__stdcall  * ThreadFun)( void   * );   // win32下的被调用的函数原型

 

下面这部分用了点Bridge模式,有点繁杂,不过是为了一个不成熟的跨平台考虑的

 

/****************************************************threadx_impl_base.h*******************************************/
#include 
" thread_def.h "
#include 
" ../misc/non_copy_able.h "

namespace  ThreadSpace  {

enum ThreadPriority { HIGH, NORMAL, LOW };        //优先级控制

struct ThreadImpl : private NonCopyable            //各个平台要提供的线程控制的Impl_基类
{
        
virtual ThreadHandle* get_handle() = 0;
        
virtual void terminate() = 0;
        
virtual bool suspend() = 0;
        
virtual bool resume() = 0;
        
virtual ThreadPriority get_priority() const = 0;
        
virtual bool set_priority(ThreadPriority tp) = 0;
        
virtual bool is_active() const = 0;
        
//virtual t_u_long wait_for_end(t_u_long timeout) = 0;
        virtual ~ThreadImpl(){ };
}
;

}


/*****************************************************threadx.h*****************************************************************/


#include 
" thread_def.h "
#include 
" threadx_impl_base.h "

namespace  ThreadSpace  {




class ThreadX : private NonCopyable
{
private:
        ThreadImpl 
*m_pimpl;
public:
        ThreadHandle
* get_handle();
        
void terminate();
        ThreadX(ThreadImpl 
*pimpl);
        
bool suspend();
        
bool resume();
        ThreadPriority get_priority() 
const;
        
bool set_priority(ThreadPriority tp);
        
bool is_active() const;
        
//t_u_long wait_for_end(t_u_long timeout = INFINITE);
        virtual ~ThreadX();
        
}
;



}



/**********************************************************threadx.cpp*********************************************************************/

#include 
" threadx.h "



namespace  ThreadSpace  {


ThreadX::ThreadX(ThreadImpl 
*pimpl) : m_pimpl(pimpl) { }

bool ThreadX::suspend()
{
        
return m_pimpl->suspend();
}


bool ThreadX::resume()
{
        
return m_pimpl->resume();
}


void ThreadX::terminate()
{
        m_pimpl
->terminate();
}


ThreadPriority ThreadX::get_priority() 
const
{
        
return m_pimpl->get_priority();
}


bool ThreadX::set_priority(ThreadPriority tp)
{
        
return m_pimpl->set_priority(tp);
}


ThreadX::
~ThreadX() { delete m_pimpl; }


bool ThreadX::is_active() const
{
        
return m_pimpl->is_active();
}



ThreadHandle
* ThreadX::get_handle()
{
        
return m_pimpl->get_handle();
}


}


/*******************************************************threadx_impl.h(在win32/)********************************************************/

#pragma  once

#include 
" ../threadx_impl_base.h "
#include 
" ../thread_expt.h "

namespace  ThreadSpace  {



class Win32ThreadImpl : public ThreadImpl
{
private:
        ThreadHandle    m_handle;
public:
        Win32ThreadImpl(HANDLE hdl, t_u_long tid, 
bool is_suspend);
        
virtual ~Win32ThreadImpl();
public:
        
virtual ThreadHandle* get_handle();
        
virtual void terminate();
        
virtual bool suspend();
        
virtual bool resume();
        
virtual ThreadPriority get_priority() const;
        
virtual bool set_priority(ThreadPriority tp);
        
virtual bool is_active()const;
        
//virtual t_u_long wait_for_end(t_u_long timeout);
}
;




}


/************************************************************threadx_impl.cpp(win32/)*****************************************************/


#include 
" threadx_impl.h "

namespace  ThreadSpace  {


Win32ThreadImpl::Win32ThreadImpl(HANDLE hdl, t_u_long tid, 
bool is_suspend) //: m_hdl(hdl), 
                                                             m_tid(tid),
                                                             m_is_suspend(is_suspend)
{
        m_handle.m_hdl 
= hdl;
        m_handle.m_tid 
= tid;
        m_handle.m_is_suspend 
= is_suspend;

}


Win32ThreadImpl::
~Win32ThreadImpl() 
{
        ::CloseHandle(m_handle.m_hdl);
}


bool Win32ThreadImpl::is_active()const
{
        t_u_long code;
        
if(::GetExitCodeThread(m_handle.m_hdl, &code) == 0throw ThreadExpt(::GetLastError());

        
return (code == STILL_ACTIVE);
}

        

void Win32ThreadImpl::terminate()
{
        ::TerminateThread(m_handle.m_hdl, 
-1);
}



bool Win32ThreadImpl::suspend()
{
        
if(m_handle.m_is_suspend) return true;

        
if(::SuspendThread(m_handle.m_hdl) == -1){
                
return false;
        }
else {
                m_handle.m_is_suspend 
= true;
                
return true;
        }

}


bool Win32ThreadImpl::resume()
{
        
if(!m_handle.m_is_suspend) return true;
        
        
if(::ResumeThread(m_handle.m_hdl) == -1){
                
return false;
        }
else{
                m_handle.m_is_suspend 
= false;
                
return true;
        }

}


ThreadPriority Win32ThreadImpl::get_priority() 
const
{
        
int res = ::GetThreadPriority(m_handle.m_hdl);
        
if(res == THREAD_PRIORITY_ERROR_RETURN) throw ThreadExpt(::GetLastError());

        
switch(res){
        
case THREAD_PRIORITY_TIME_CRITICAL:
        
case THREAD_PRIORITY_HIGHEST:
                
return HIGH;
        
case THREAD_PRIORITY_ABOVE_NORMAL:
        
case THREAD_PRIORITY_NORMAL:
        
case THREAD_PRIORITY_BELOW_NORMAL:
                
return NORMAL;
        
default:
                
return LOW;                //case THREAD_PRIORITY_LOWEST:
                                        
//case THREAD_PRIORITY_IDLE:
        }

}


bool Win32ThreadImpl::set_priority(ThreadPriority tp)
{
        
switch(tp){
        
case HIGH:
                
return (::SetThreadPriority(m_handle.m_hdl, THREAD_PRIORITY_HIGHEST) != 0);
        
case LOW:
                
return (::SetThreadPriority(m_handle.m_hdl, THREAD_PRIORITY_LOWEST) != 0);
        
default:
                
return (::SetThreadPriority(m_handle.m_hdl, THREAD_PRIORITY_NORMAL) != 0);
        }

}



/*t_u_long Win32ThreadImpl::wait_for_end(t_u_long timeout)
{
        return ::WaitForSingleObject(m_handle.m_hdl, timeout);
}
*/



ThreadHandle
* Win32ThreadImpl::get_handle()
{
        
return &m_handle;
}







}



以上是大概齐的框架,下面请看如何启动一个线程

 

 

/***************************************************************aux_fun.h*******************************************************/
#pragma  once

#include 
" thread_def.h "


namespace  ThreadSpace  {


class ThreadX;

ThreadX
* create_thread(ThreadFun proc, void *param, const ThreadAttr &attr);   //创建一个线程(在各文件夹下有不同的实现)

void free_thread(ThreadX *&pthread);//delete ThreadX*... 同上

t_u_long wait_thread(ThreadX 
*pthread, t_u_long timeout = INFINITE);  //等待一个线程结束

t_u_long wait_multi_thread(ThreadX 
**ppthread, size_t count, bool wait_all = true, t_u_long timeout ); 等待所有一组结束


}



/**************************************************axu_fun.cpp (win32/)************************************************/

#include 
" ../aux_fun.h "
#include 
" ../threadx.h "
#include 
" threadx_impl.h "


#include 
< vector >
#include 
< cassert >
namespace  ThreadSpace  {




ThreadX
* create_thread(ThreadFun proc, void *param, const ThreadAttr &attr)
{
        t_u_int32 tid;
        HANDLE hdl 
= (HANDLE)_beginthreadex(0, attr.stack_size, proc, param, attr.create_flags, &tid);
        
if(hdl == 0throw(ThreadExpt(errno));
        
        
return new ThreadX(new Win32ThreadImpl(hdl, tid, (attr.create_flags == CREATE_SUSPENDED)));

}



void free_thread(ThreadX *&pthread) 
{
        assert(pthread 
!= 0);
        
try{
                delete pthread;
                pthread 
= 0;
                
        }
catch(...)
        
{

        }

}




t_u_long wait_thread(ThreadX 
*pthread, t_u_long timeout)
{
        assert(pthread 
!= 0);
        t_u_long res 
= ::WaitForSingleObject(pthread->get_handle()->m_hdl, timeout);
        
if(res == WAIT_FAILED) throw (ThreadExpt(::GetLastError()));
        
return res;
}


t_u_long wait_multi_thread(ThreadX 
**ppthread, size_t count, bool wait_all, t_u_long timeout)
{
        assert(ppthread 
!= 0);
        std::vector
<HANDLE> vhdl;
        
for(size_t i = 0; i < count; ++i)
                vhdl.push_back(ppthread[i]
->get_handle()->m_hdl);

        t_u_long res 
= ::WaitForMultipleObjects(count, &vhdl[0], wait_all, timeout);

        
if(res == WAIT_FAILED) throw(ThreadExpt(::GetLastError()));

        
return res;



}


 

恩,下面是关键了,就是我们如何直接把一成员函数当做线程来执行平是我们的习惯是

 


class  Test
{
public:
        
void test() { printf("xxxxxxxxx"); } //成员函数
        static unsigned int WINAPI ThreadFun(void *pvoid)
        
{
                Test 
*ptest = static_cast<Test*>(pvoid);
                ptest
->test();
                
return 0;
        }

}
;

int  main()
{
        Test test;
        HANDLE hdl 
= (HANDLE)_beginthreadex(00, Test::ThreadFun, (void*)&test, 00);
    
        cin.
get();        
        
return 0
}

如果我们希望直接启动这个成员函数呢?OK,下面有些复杂的模板定义,请注意,这些东西也许无意义,但很有意思

 

 

#pragma  once

#include 
< memory >

namespace  ThreadSpace  {

        
template
<class T, class MF, class P>
struct ThreadInfo
{
        T     
*ptype;        //传递进来的那个类的指针;
        MF    mem_fun;    //类成员函数指针
        P    *param;    //参数指针;
        
        ThreadInfo(T 
*pt, MF mf, P *pa) : ptype(pt), mem_fun(mf), param(pa) { }
}
;



template
<class ExecImpl>
class MemFunExector
{
private:
        typedef typename ExecImpl::HandleType        HandleType; 
//见下面的ExecImpBase注释
        typedef typename ExecImpl::Result            Result;
        typedef typename ExecImpl::Param            Param;    
private:
        template
<class C>//这个是那个被执行的线程函数,根据被实例化的不同的ThreadInfo模板来作实例化
        static Result ThreadFunc(Param param)
        
{
                std::auto_ptr
<C> p_info((C*)param);
                
//这样,根据调用一个函数指针来调用相应的成员函数
                return ((p_info->ptype)->*(p_info->mem_fun))(*p_info->param);
        }



public://首先这个模板函数接受一个类的指针,这个类的成员函数指针和成员函数参数
        template<class Type, class MFun, class MParam> 
        HandleType 
operator()(Type *pt, MFun fun, MParam &param)
        
{
                
//ThreadInfo<Type, MFun, MParam>相应的ThreadInfo实例化,这个类同样作为记录参数信息来用的
                
//ThreadFunc再根据上面的ThradInfo类作实例化
                return ExecImpl()(ThreadFunc<ThreadInfo<Type, MFun, MParam> >, (Param)(new ThreadInfo<Type, MFun, MParam>(pt, fun, &param)));
        }


        template
<class Type, class MFun, class MParam, class ATTR> 
        HandleType 
operator()(Type *pt, MFun fun, MParam &param, ATTR &attr)
        
{
                
return ExecImpl(attr)(ThreadFunc<ThreadInfo<Type, MFun, MParam> >, (Param)(new ThreadInfo<Type, MFun, MParam>(pt, fun, &param)));
        }

}
;


//这个类是为了提供不同平台的线程启动函数兼容的,每个平台都应该有一个不同的派生类
template<class H, class R, class P>
struct    ExecImpBase
{
        typedef H            HandleType;    
//注意,这个是启动那个成员函数返回的句柄,例如ThreadX*
        typedef R            Result;        //这个是那个成员函数的返回值,类似unsigned int
        typedef P            Param;     //那个成员函数的参数,类似void*p等,以后定义
        typedef Result    (*PF)(Param);
        
        
virtual HandleType    operator()(PF pf, Param param) = 0;
}
;


}





 

根据平台定义相应的Traits类

#pragma  once


#include 
" ../mem_fun_exector.h "


namespace  ThreadSpace  {

class ThreadX;
struct ThreadAttr;

struct ExecutorWin32 : public ExecImpBase<ThreadX*, unsigned intvoid*>
{
        
const ThreadAttr        &m_attr;
        
        ExecutorWin32(
const ThreadAttr &attr);
        
        
virtual HandleType operator()(PF pf, Param param);
        
}
;


#define MFExecutor(type, mfun, param, attr) 
        MemFunExector
<ExecutorWin32>()((type), (mfun), (param), (attr))


}

 

 


class  Test
{
public:
        
void test(void *p) { printf("xxxxxxxxx"); } //成员函数  注意,这个和上个不同,加了个void*p作为参数,是为了兼容那个模板
       }
;

int  main()
{
        Test test;
        ThreadAttr attr;
        
void *= 0;
        MFExecutor(
&test, Test::test, p, attr);
        cin.
get();        
        
return 0
}

 

OK,这部分就到此为止了,有什么错误请各位读者指教,有喜欢模板的朋友请加我QQ 2070341,明天我会贴IOCP的相关类或者Tracker requester类的代码,请各位看官支持,谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FC常用类及其成员函数 CRuntimeClass结构 在CRuntimeClass结构中定义了类名、对象所占存储空间的大小、类的版本号等成员变量及动态创建对象、派生关系判断等成员函数。每一个从CObject类派生的类都有一个CRuntimeClass结构同它关联,以便完成在运行时得到对象的信息或基类的信息。 要使用CRuntimeClass结构,必须结合使用RUNTIME_CLASS()宏和其他有关运行时类型识别的MFC宏。 CCmdTarget类 (1)消息发送 MFC应用程序为每个CCmdTarget派生类创建一个称为消息映射表的静态数据结构,可将消息映射到对象所对应的消息处理函数上。 (2)设置光标 BeginWaitCursor() 将光标改为沙漏形状; EndWaitCursor() 将光标改回到之前的形状; RestoreWaitCursor()用于将光标还原为等待状态。 (3)支持自动化 CCmdTarget类支持程序通过COM接口进行交互操作,自动翻译COM接口的方法。 CWinThread类 由CCmdTarget派生,主要工作是创建和处理消息循环。 CWinApp类 从CWinThread类派生,成员函数InitApplication()、InitInstance()、Run()。 在InitInstance()函数中,创建了一个单文档模板类或多文档模板类(CDocTemplate)的对象,并且在文档模板的构造函数中,系统定义的宏RUNTIME_CLASS创建了文档类对象,框架窗口类对象和视图类对象. 在MFC应用程序中有且仅有一个CWinApp派生类的对象,代表程序运行的主线程,代表应用程序本身。 CWnd类 由CCmdTarget类直接派生,是MFC中最基本的GUI对象。公共变量m_hWnd用于存放供API函数调用的窗口句柄。 CframeWnd类 从CWnd类派生而来,主要用来掌管一个窗口。其对象是一个框架窗口,包括边界、标题栏、菜单、最大化按钮、最小化按钮和一个激活的视图。常用成员函数: GetActiveDocument():得到当前文档的指针。 GetActiveView(): 得到当前视图的指针。 SetActiveView(): 激活一个视图。 GetTitle(): 得到框架窗口的标题。 SetTitle(): 设置框架窗口的标题。 SetMessageText(): 设置状态栏文本。 CDocument类 从CCmdTarget派生,作为用户文档的基类,代表了用户存储或打开一个文件。主要功能是把对数据的处理从对用户的界面处理中分离出来,同时提供一个与视图类交互的接口。常用的成员函数有: OnNewDocument(): 建立新文档。 OnOpenDocument(): 打开一个文档。 OnCloseDocument(): 关闭文档。 OnSaveDocument(): 保存文档。 UpdateAllView(): 通知所有视图文档被修改。 SaveModified(): 设置文档修改标志。 CView类 从CWnd类派生而来,是MFC视图类和用户视图类的基类。CWnd::Invalidate()或CWnd::InvalidateRect()可以刷新视图。常用函数有: GetDocument(): 视图类对象访问文档类对象中的数据的. OnDraw(): 这个函数有一个指向CDC类的指针参数, 通过它可能直接调用CDC类上显示数据和图形. 在应用程序窗口出现在及大小发生变化时, 系统将自动调用OnDraw函数 OnInitialUpdate(): 作一些初始化工作. 程序员的主要工作 (1) 重写WinApp派生类的虚函数InitInstance.在这个函数中,按自己的需要创建和显示窗口. (2) 在CDocument的派生类中,声明程序所需的数据和对这些数据进行必要操作的接口函数. (3) 在CViwe类的派生类中编写处理消息的代码.如果在消息处理中需要文档的数据,应该调用该类的成员函数GetDocument来获取文档对象,然后通过文档对象的接口函数对文档中的数据进行操作. (4) 在CViwe类的派生类中的OnDraw函数中编写窗口重绘时的代码. Gilbert觉得以上是很大的类, 下面介绍一些小类: CRect类 矩形类,拥有四个成员变量:top, left, bottom, right。分别表是左上角和右下角的坐标。可以通过以下的方法构造: CRect( int l, int t, int r, int b ); 指明四个坐标 CRect( const RECT& srcRect ); 由RECT结构构造 CRect( LPCRECT lpSrcRect ); 由RECT结构构造 CRect( POINT point, SIZE size ); 有左上角坐标和尺寸构造 CRect( POINT topLeft, POINT bottomRight ); 有两点坐标构造 它的几个成员函数: int Width( ) const; 得到宽度 int Height( ) const; 得到高度 CSize Size( ) const; 得到尺寸 CPoint& TopLeft( ); 得到左上角坐标 CPoint& BottomRight( ); 得到右下角坐标 CPoint CenterPoint( ) const; 得当中心坐标 此外矩形可以和点(CPoint)相加进行位移,和另一个矩形相加得到“并”操作后的矩形。 CPoint类 点的坐标,有两个成员变量:x, y。可以和另一个点相加。 CString类 表示可变长度的字符串。使用CString可不指明内存大小,CString会根据需要自行分配。几个成员函数: GetLength 得到字符串长度 operator + 相当于strcat Compare 比较 CompareNoCase 不区分大小写比较 MakeUpper 改为小写 MakeLower 改为大写
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值