代码改变世界

Windows _beginthreadex 线程类与线程池

2015-02-04 14:41  sylar_liang  阅读(507)  评论(0编辑  收藏  举报

一.线程类

》》函数

1.创建线程

void startThread(bool bSuspend = false) 

2.停止线程

virtual void endThread() = 0 

3.挂起线程

void suspendThread() 

4.恢复线程

void resumeThread() 

5.获取线程句柄

inline HANDLE GetHandle(){return m_hThread;} 

6.线程的入口函数

static unsigned int __stdcall m_fnThread(void *ptr) 

6.执行某些操作

virtual void run() = 0

》》数据

HANDLE m_hThread;

bool m_bSuspend;

// MyThread.h
#pragma once

#include "CommonHead.h"

class MyThread
{
public:
    MyThread(void);
    virtual ~MyThread(void); // 作为基类,析构函数必须定义为虚函数

    void startThread(bool bSuspend = false); // 启动线程时是否为挂起状态
    virtual void endThread() = 0; // 纯虚函数
    
    void suspendThread(); // 挂起线程
    void resumeThread(); // 恢复线程

    inline HANDLE GetHandle() // 获取线程句柄
    {
        return m_hThread;
    }
protected:
    static unsigned int __stdcall m_fnThread(void *ptr); // 线程函数入口
    virtual DWORD run() = 0;
private:
    HANDLE m_hThread; // 线程句柄    
};
// MyThread.cpp
#include <assert.h>
#include <process.h> // _endthread() 需要用到
MyThread::MyThread(
void) :m_hThread(INVALID_HANDLE_VALUE) { } MyThread::~MyThread(void) { if( INVALID_HANDLE_VALUE != m_hThread ) { CloseHandle(m_hThread); m_hThread = INVALID_HANDLE_VALUE; } } // 线程函数入口 unsigned int __stdcall MyThread::m_fnThread(void *ptr) { MyThread * pThread = (MyThread *)ptr; DWORD ret = 0; if(pThread) { ret = pThread->run(); _endthread(); } return ret; } // 启动线程时是否为挂起状态 void MyThread::startThread(bool bSuspend /*= false*/) { assert( INVALID_HANDLE_VALUE == m_hThread); if( INVALID_HANDLE_VALUE == m_hThread ) { unsigned threadID = 0; m_hThread = (HANDLE)_beginthreadex(NULL, 0, m_fnThread, (void *)this, (bSuspend ? CREATE_SUSPENDED : 0), &threadID); } } // 挂起线程 void MyThread::suspendThread() { ::SuspendThread(m_hThread); } // 恢复线程 void MyThread::resumeThread() { ::ResumeThread(m_hThread); }

其中:

区分 CreateThrad 与 _beginthreadex 函数
HANDLE  WINAPI  CreateThread(
LPSECURITY_ATTRIBUTES  lpThreadAttributes, // 线程内核对象的安全属性,一般传入NULL表示使用默认设置。
SIZE_T  dwStackSize, // 线程栈空间大小。传入0表示使用默认大小(1MB)。
LPTHREAD_START_ROUTINE  lpStartAddress, // 新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
LPVOID  lpParameter, // 传给线程函数的参数。
DWORD  dwCreationFlags, // 线程启动时是挂起还是运行状态.0 表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行
LPDWORD  lpThreadId // 返回线程的ID号,传入NULL表示不需要返回该线程ID号。
);
配套线程等待函数
DWORD  WINAPI  WaitForSingleObject(
HANDLE  hHandle, // 要等待的内核对象
DWORD  dwMilliseconds // 最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入 INFINITE 表示无限等待。
);
返回值
在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED

 

unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist, /* 这个就是传给线程函数的参数的指针 */
unsigned initflag,
unsigned *thrdaddr );

尽量使用_beginthreadex()来代替使用CreateThread()
_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。
事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。
因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。

 

二、线程池

需要上面的类

class MyThread;

头文件支持
#include <process.h>

》》函数

1.增加线程

void AddThread(MyThread *pthread, bool bSuspend)

2.批量开启线程

void BatchStartThread()

3.批量停止线程

void BatchStopThread()

4.释放所有线程

void Release()

5.设置自动释放

void SetAutoRelease(bool bVal)

 

》》变量

vector<MyThread *> m_threadList;

bool m_bAutoRelease;

// MyThreadPool.h
#pragma once

//#include "MyThread.h" // 头文件不要包含 .h,直接定义一个 class MyThread;在.cpp中包含

  #include <vector>
  using namespace std;

  class MyThread; // Add


class MyThreadPool { public: MyThreadPool(void); ~MyThreadPool(void); void AddThread(MyThread *thread, bool bSuspend = false); // 增加线程 void BatchStopThread(); // 批量停止线程 void BatchStartThread(); // 批量启动线程 void Release(); // 释放全部线程 void SetAutoRelease(bool bVal); // 是否自动释放线程 private: bool m_bAutoRelease; // 自动释放 vector<MyThread *> m_threadList; };
// MyThreadPool.cpp
#include "MyThreadPool.h"
#include "MyThread.h" // 在 .cpp 中添加头文件

MyThreadPool::MyThreadPool(void)
    :m_bAutoRelease(true)
{
}


MyThreadPool::~MyThreadPool(void)
{
    Release();
}

// 增加线程
void MyThreadPool::AddThread(MyThread *pthread, bool bSuspend /*= false*/)
{
    m_threadList.push_back(pthread);
    pthread->startThread(bSuspend);
}

// 批量停止线程
void MyThreadPool::BatchStopThread()
{
    MyThread * pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        pthread->endThread(); // 结束线程

        WaitForSingleObject(pthread->GetHandle(), INFINITE);
        
    }
}

// 批量启动线程
void MyThreadPool::BatchStartThread()
{
    MyThread * pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        pthread->resumeThread(); // 恢复线程
    }
}

// 释放全部线程
void MyThreadPool::Release()
{
    BatchStopThread();

    MyThread *pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        if(m_bAutoRelease)
            delete pthread;
    }

    m_threadList.clear();
}

// 是否自动释放线程
void MyThreadPool::SetAutoRelease(bool bVal)
{
    m_bAutoRelease = bVal;
}