2013-05-12 1 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

+0

@ user2348816 Я не могу использовать внешние библиотеки, кроме стандартной библиотеки и библиотеки шаблонов, которая поставляется с C++ 11. Это для класса C++, который я делаю – footy

+1

Является ли заданием создать оболочку? Потому что теперь есть [std :: thread] (http://en.cppreference.com/w/cpp/thread/thread). – Collin

ответ

1

Так что

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

является указателем на функцию, но вам нужен член указатель функции

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

Для вызова указателя функции члена вам нужен объект, и вы должны вызвать его со следующим синтаксисом:

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

Примечания ->* синтаксиса здесь.

Поэтому я добавил параметр T* self к TupleUnpack<>::unpack и назвал его в Call<>::dispatch с obj членом. Теперь я мог бы заменить функцию test параметром mem в NewThread.

Вот патч:

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