若需要執行一個可能會花些時間的函式 (e.g., 有 blocking read) 但又不希望停住目前的 thread, 解法之一是產生一個新 thread, 然後在該 thread 執行原本欲執行的函式。先來看看 Python 遇到這種情況要怎麼作:
import thread
class A(object):
def out(self):
print 'A.out()'
a = A()
thread.start_new_thread(A.out, (a,)) # 就這行
相當地直覺。
在 C++ 裡想要執行 non-static member function 的話, 就有點惱人。解決的方法很多, 以下是我土法煉鋼的陽春解法。看 code 即可明白, 關鍵是使用 template 以及 pointer-to-member function。算是一個練習 template 的好題目, 還有了解 C++ 編譯時期多型的威力。
t.h
#include <pthread.h>
template<class T>
struct MethodWrapper {
typedef void(T::*Method)();
MethodWrapper(T *object, Method method)
: m_object(object), m_method(method) {}
void Run() { (m_object->*m_method)(); }
T *m_object;
Method m_method;
};
// The interface for pthread's usage.
template <class T>
void* CallMethod(void *v) {
MethodWrapper<T> *p = (MethodWrapper<T>*)v;
p->Run();
delete p;
return NULL;
}
template <class T>
inline pthread_t RunInNewThread(MethodWrapper<T>* param) {
pthread_t th;
pthread_create(&th, NULL, CallMethod<T>, (void*)param);
return th;
}
f.h
#include <iostream>
#include <sys/syscall.h>
struct A {
void Out() {
std::cout << "tid=" << syscall(__NR_gettid)
<< " A.Out()" << std::endl;
}
};
f.cpp
#include "f.h"
#include "t.h"
/* Compilation: g++ f.cpp -o f -g -Wall -lpthread */
int main(void) {
A a;
a.Out(); // Direct call.
MethodWrapper<A>* m = new MethodWrapper<A>(&a, &A::Out);
m->Run(); // Called via the wrapper.
CallMethod<A>(m); // Called via a template function.
m = new MethodWrapper<A>(&a, &A::Out);
pthread_t th = RunInNewThread(m); // Called in a new thread.
pthread_join(th, NULL);
return 0;
}
C++ passing method pointer as template argument 提到用 boost::function0 的解法, 以後再來讀吧。
2012-12-02 更新
Ken 和 command 補充了簡單的作法:
Btw, 這篇文章主要目的是練習 template, 另外在這裡補上若要土法煉鋼地支援參數時該怎麼辦。