一个类里的函数,通常要作为线程的入口函数,必须把它指定为static类型。
static类型的类成员函数,并不具有this指针,也不能访问到protected或private类型的类成员。
因为以上的不便,我们会想,怎样把一个普通的类成员函数,当作线程的“入口函数”呢?
方法还是有的,具体说来:
1. 创建一个线程,将类指针this和“入口函数”当作参数传入, 其实这里的“入口函数”已经不是线程真正的入口函数了.
2. 利用->*操作符, 调用该“入口函数”, (this->*入口函数) (arg)
得益于c++的强大模版, 下面是该过程的一个封装, 使用也很简单:
相对于pthread的 pthread_create (thread_id, attr, entry, arg),
如果要把类成员函数当作线程入口, 只需要多加一个this,
thread_proxy(this, thread_id, attr, entry, arg)
/
//代码
#include <cstdio>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
template <class T>
class thread_proxy_imp
{
protected:
typedef struct
{
T *obj;
void (T::*start_routine)(void *);
void *arg;
sem_t sem;
} thread_param;
static void *thread_proxy_entry (void *arg)
{
thread_param *param_ptr = static_cast<thread_param *> (arg);
thread_param param = *param_ptr;
sem_post (¶m_ptr->sem);
/* 注意 ->* 操作符 */
(param.obj->*param.start_routine) (param.arg);
}
public:
int pthread_create (
T *obj,
pthread_t *thread,
const pthread_attr_t *attr,
void (T::*start_routine)(void *),
void *arg)
{
int rt;
thread_param param = {obj, start_routine, arg};
/* 为防止param在新线程使用它之前被析构,加上一个semaphore. */
sem_init (¶m.sem, 0, 0);
rt = ::pthread_create (thread, attr, &thread_proxy_imp::thread_proxy_entry, static_cast<void *> (¶m));
sem_wait (¶m.sem);
sem_destroy (¶m.sem);
return rt;
}
};
template <class T>
int thread_proxy (
T *obj,
pthread_t *thread,
const pthread_attr_t *attr,
void (T::*start_routine)(void *),
void *arg)
{
return thread_proxy_imp<T> ().pthread_create (obj, thread, attr, start_routine, arg);
}
class C
{
public:
pthread_t m_thread;
int create_thread ()
{
thread_proxy(this, &m_thread, NULL, &C::thread_entry, (void *) 56);
}
protected:
void thread_entry (void *arg)
{
for (int i = 0; i < 10; i++)
{
printf ("arg: %d\n", arg);
sleep (1);
}
};
};
int main ()
{
C c;
c.create_thread ();
pthread_join (c.m_thread, NULL);
printf ("exit ...\n");
return 0;
}
===================================================================================
[问题提出]
如何用非静态的类成员函数,作为线程函数!
[问题解答]
可以使用它的隐藏参数,作为线程函数的参数,这样就可匹配参数!
[程序实现]
#include <windows.h>
#include <conio.h>
#include <stdio.h>
class t
{
public:
void Run();
t();
protected:
char c[256];
DWORD WINAPI ThreadFunc();
};
typedef DWORD (WINAPI t::* pThreadFunc)();
t::t()
{
strcpy(c, "Welcome to use thread proc");
}
DWORD WINAPI t::ThreadFunc()
{
MessageBox(NULL, c, "xixi", MB_OK);
return 0;
}
typedef DWORD (WINAPI * PTHREADFUNC)(LPVOID);
void t::Run()
{
pThreadFunc p = ThreadFunc;
DWORD dwAddress;
memcpy(&dwAddress,&p,sizeof(p));
PTHREADFUNC p1;
memcpy(&p1, &dwAddress, sizeof(p1));
DWORD dwTID;
HANDLE hf;
hf = CreateThread(NULL, 0, p1, this, 0, &dwTID);
if (hf){
CloseHandle(hf);
}
}
void main()
{
t t1;
t1.Run();
getch();
}
==================================================================================
使用就太简单了:任何含有线程成员函数的类,之需要做成这个类的派生类,
然后就可以随时使用 StartThread(TMethod fMethod, TParam& rParam) 函
数,第一个参数是要运行的成员函数,第二个参数是欲调用该成员函数的参
数。呵呵,连 this 都不用传了!
参数这里以后还要继续改进,使得对无参数等情况支持得更好,过两天有空
再帖吧。
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
class ClassWithThreadMethod {
public:
template <class TMethod, class TParam> class CThreadMethod {
public:
typedef int(__stdcall ClassWithThreadMethod::*IMethod)(TParam);
uintptr_t StartThread(ClassWithThreadMethod* pObj, TMethod fMethod,
TParam& rParam) {
uintptr_t hThread = 0;
if (pObj && fMethod) {
pObject = pObj, fIMethod = (IMethod)fMethod, oParam = rParam;
hThWait = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread = _beginthreadex(NULL, 0, ThreadFunc, this, 0, &hThread);
CloseHandle((WaitForSingleObject(hThWait ,INFINITE), hThWait));
}
return hThread;
}
private:
static unsigned __stdcall ThreadFunc(void* pThreadMethod) {
CThreadMethod TMCopy = *((CThreadMethod*)pThreadMethod);
#include <iostream>
using namespace std;
class ClassWithThreadMethod {
public:
template <class TMethod, class TParam> class CThreadMethod {
public:
typedef int(__stdcall ClassWithThreadMethod::*IMethod)(TParam);
uintptr_t StartThread(ClassWithThreadMethod* pObj, TMethod fMethod,
TParam& rParam) {
uintptr_t hThread = 0;
if (pObj && fMethod) {
pObject = pObj, fIMethod = (IMethod)fMethod, oParam = rParam;
hThWait = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread = _beginthreadex(NULL, 0, ThreadFunc, this, 0, &hThread);
CloseHandle((WaitForSingleObject(hThWait ,INFINITE), hThWait));
}
return hThread;
}
private:
static unsigned __stdcall ThreadFunc(void* pThreadMethod) {
CThreadMethod TMCopy = *((CThreadMethod*)pThreadMethod);
SetEvent(((CThreadMethod*)pThreadMethod)->hThWait);
return (TMCopy.pObject->*TMCopy.fIMethod)(TMCopy.oParam);
}
IMethod fIMethod;
TParam oParam;
HANDLE hThWait;
ClassWithThreadMethod* pObject;
};
template <class TMethod, class TParam>
HANDLE StartThread(TMethod fMethod, TParam& rParam)
{
CThreadMethod<TMethod, TParam> oTMethod;
return (HANDLE)oTMethod.StartThread(this, fMethod, rParam);
}
};
int g_nGlobal=0;
class CMyThread : public ClassWithThreadMethod
{
public:
CMyThread() : m_nNumber(0) { }
struct DualParam {
int nParam1;
int nParam2;
} oParam;
int __stdcall MyThreadMethod(int nParam1, int nParam2)
{
m_nNumber = nParam1 * 1000 + nParam2 + 1;
g_nGlobal = nParam2 * 1000 + nParam1 + 1;
return 0;
}
void TestThreadMethod() {
oParam.nParam1 = 3;
oParam.nParam2 = 9;
HANDLE hThread = StartThread(MyThreadMethod, oParam);
CloseHandle((WaitForSingleObject(hThread,INFINITE), hThread));
}
int m_nNumber;
};
CMyThread MyThread;
int main(int argc, char* argv[])
{
MyThread.TestThreadMethod();
cout << g_nGlobal << " " << MyThread.m_nNumber << endl;
return 0;
}
转自:http://hi.baidu.com/%B8%DF%C9%BD%C1%F7%CB%AE/blog/item/6fa91a4c27c584ffd62afc46.html