c++templatesc++11variadic-templatesg++-4.7

Generic thread c wrapper function for c++


Here I have written a thread wrapper for c thread function pthread_create(). It will allow calling any method on any object and passing any number of arguments to that method. The API is:

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

Below is the template:

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;
}

Below is the CPP file:

#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;
}

I am trying to call the x::method() with the arguments. As you can see I have a test() function which is similar to x::method() just to demonstrate that my thread is working. But I want to be able to call the x::method(). Could anyone please guide me?

In Essence my current output is:

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

I want my output to be

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

Solution

  • So this

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

    is a function pointer, but you need a member function pointer

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

    For calling a member function pointer you need an object and you have to call it with the following syntax:

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

    Note ->* syntax here.

    So I added a T* self parameter to TupleUnpack<>::unpack and called it in Call<>::dispatch with the obj member. Now, I could replace the test function with the mem parameter in NewThread.

    Here is a patch:

    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) ;