2013-05-12 38 views
1

這裏我寫了一個線程包裝的c線程函數pthread_create()。它將允許在任何對象上調用任何方法並將任意數量的參數傳遞給該方法。 API是:C++的通用線程c包裝函數

template <typename T, typename R, typename... ATs> 
pthread_t NewThread(T *obj, R (T::*mem)(ATs...), ATs... args); 

下面是模板:

template<unsigned int i> 
class TupleUnpack 
{ 
    public: 
    template<typename R, typename ...ATs, typename ...T_function_arguments> 
    inline static R unpack (R (*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple, 
    T_function_arguments ...function_arguments) 
    { 
     return TupleUnpack<i-1>::unpack (function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...); 
    }      
}; 

template<> 
class TupleUnpack<0> 
{ 
    public: 
    template<typename R, typename ...ATs, typename ...T_function_arguments> 
    inline static R unpack (R    (*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple, 
    T_function_arguments    ...function_arguments) 
    { 
     return function (function_arguments...); 
    }   
}; 
class CallCaller 
{ 
    virtual bool dispatch (void)=0; 
}; 

template<typename T,typename R,typename ...ATs> 
class Call : public CallCaller 
{ 
    public:  
    Call (T *obj,R (*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {} 

    ~Call() {} 
    bool dispatch (void) 
    { 
     return TupleUnpack<sizeof ...(ATs)>::unpack (this->function, this->tuplearg); 
    } 

    private: 
    std::tuple<ATs...> tuplearg; 
    R (*function) (ATs...); 

    T *obj; 
}; 

void *test(int d,double sf) 
{ 
    std::cout<<"yay my thread runs d="<<d<<" sf="<<sf<<std::endl;  
} 

template<typename T,typename R,typename ...ATs> 
void* stub (void* vp) 
{ 

    Call<T,R,ATs...>* call = static_cast<Call<T,R,ATs...>*>(vp); 
    call->dispatch();  
    delete call;   
    pthread_exit (0); 

} 
template <typename T, typename R, typename... ATs> 
pthread_t NewThread(T *ob, R (T::*mem)(ATs...), ATs... args) 
{ 
    pthread_t tid; 
    R (*func) (ATs...); 
    Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,&test,args...); 

    pthread_create(&tid, nullptr, stub<T,R,ATs...>, task) ; 

    return tid; 
} 

下面是CPP文件:

#include <tr1/tuple> 
#include <utility> 
#include <iostream> 
#include <pthread.h> 
#include <tuple> 
#include <type_traits> 
#include <utility> 
#include "NewThread.hpp" 

class X 
{ 
    public: 
    void *method(int a, double x) 
    { 
     std::cout<<"yay my tread runs a="<<a<<" x="<<x<<std::endl; 
    } 

}; 

int main() 
{ 
    X x; 
    int i; 
    pthread_t tid = NewThread(&x, &X::method, 1234, 3.14); 



    pthread_join(tid,NULL); 

    std::cout<<"Thread Ended "<<tid<<std::endl; 
    return 0; 
} 

我想打電話給x::method()的論據。正如你所看到的,我有一個test()函數,它與x::method()類似,只是爲了證明我的線程正在工作。但我希望能夠撥打x::method()。任何人都可以請指導我?

在本質上我的電流輸出爲:

yay my thread runs d=1234 sf=3.14 
Thread Ended 139766222432000 

我希望我的輸出是

yay my thread runs a=1234 x=3.14 
Thread Ended 139766222432000 
+1

爲什麼不使用[提振::線程(http://www.boost.org/libs/thread)和簡化你的生活? – user2348816 2013-05-12 01:08:02

+0

@ user2348816我不能使用C++ 11附帶的標準庫和模板庫以外的任何外部庫。這是爲我正在做的C++類 – footy 2013-05-12 01:11:46

+1

是創建包裝的任務?因爲現在有[std :: thread](http://en.cppreference.com/w/cpp/thread/thread)。 – Collin 2013-05-12 01:27:20

回答

1

所以這

R (*function) (ATs...); 

是一個函數指針,但你需要一個成員功能指針

R (T::*function) (ATs...); 

用於調用成員函數指針,你需要一個對象,你必須使用以下語法來調用它:

self->*function(function_arguments...); 

注意->*語法在這裏。

因此,我添加了一個T* self參數TupleUnpack<>::unpack,並在Call<>::dispatchobj成員進行了調用。現在,我可以用NewThread中的mem參數代替test函數。

這裏是一個補丁:

diff --git a/NewThread.hpp b/NewThread.hpp 
index e121294..768f7d9 100644 
--- a/NewThread.hpp 
+++ b/NewThread.hpp 
@@ -5,12 +5,12 @@ template<unsigned int i> 
class TupleUnpack 
{ 
    public: 
- template<typename R, typename ...ATs, typename ...T_function_arguments> 
- inline static R unpack (R (*function) (ATs...), 
+ template<typename T, typename R, typename ...ATs, typename ...T_function_arguments> 
+ inline static R unpack (T* self, R (T::*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple, 
    T_function_arguments ...function_arguments) 
    { 
-  return TupleUnpack<i-1>::unpack (function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...); 
+  return TupleUnpack<i-1>::unpack (self, function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...); 
    }      
}; 

@@ -18,12 +18,12 @@ template<> 
class TupleUnpack<0> 
{ 
    public: 
- template<typename R, typename ...ATs, typename ...T_function_arguments> 
- inline static R unpack (R    (*function) (ATs...), 
+ template<typename T, typename R, typename ...ATs, typename ...T_function_arguments> 
+ inline static R unpack (T* self, R (T::*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple, 
    T_function_arguments    ...function_arguments) 
    { 
-  return function (function_arguments...); 
+  return (self->*function) (function_arguments...); 
    }   
}; 
class CallCaller 
@@ -35,19 +35,17 @@ template<typename T,typename R,typename ...ATs> 
class Call : public CallCaller 
{ 
    public:  
- Call (T *obj,R (*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {} 
+ Call (T *obj,R (T::*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {} 

    ~Call() {} 
    bool dispatch (void) 
    { 
-  return TupleUnpack<sizeof ...(ATs)>::unpack (this->function, this->tuplearg); 
+  return TupleUnpack<sizeof ...(ATs)>::unpack(obj, this->function, this->tuplearg); 
    } 

    private: 
    std::tuple<ATs...> tuplearg; 
- R (*function) (ATs...); 
+ R (T::*function) (ATs...); 

    T *obj; 
}; 
@@ -71,8 +69,7 @@ template <typename T, typename R, typename... ATs> 
pthread_t NewThread(T *ob, R (T::*mem)(ATs...), ATs... args) 
{ 
    pthread_t tid; 
- R (*func) (ATs...); 
- Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,&test,args...); 
+ Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,mem,args...); 

    pthread_create(&tid, nullptr, stub<T,R,ATs...>, task) ; 
+0

令人敬畏的工作!我會+10這個 – footy 2013-05-12 03:38:58