Threading with inheritance in multiple derived classes
Mar 14, 2009 at 2:57am UTC
hi all!
i have a question regarding how to achieve threading with inheritance using multiple derived classes. originally i was using this code to work with 1 specific class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include <pthread.h>
#include <iostream>
using namespace std;
class theClass
{
public :
theClass( void );
pthread_t startThread( void ((theClass::*)(void *)), void * );
static void * doStartThread( void * );
void * theFunction( void * );
};
struct thStruct
{
theClass* obj;
void (theClass::*func)(void *);
void * args;
};
pthread_t theClass::startThread( void ((theClass::*func)(void *)), void * args )
{
pthread_t th; //thread structure to return to the caller.
thStruct* ts = new thStruct(); //class specific information.
ts->func = func; //target threaded member-function.
ts->obj = this ; //object containing the target threaded function.
ts->args = args; //parameters to pass.
pthread_create( &th, NULL, &theClass::doStartThread, (void *)ts ); //invoking the threaded function.
return th;
}
void * theClass::doStartThread( void * ptr )
{
thStruct* ts = (thStruct*)ptr; //retriving the class specific information.
theClass* obj = ts->obj;
void ((theClass::*func)(void *)) = ot->func;
(obj->*func)( ts->args ); //calling the target member function, which is now in a seperate thread.
delete ts; //cleaning up.
return 0; //returning a dummy value.
}
theClass::theClass( void )
{
this ->startThread( &theClass::theFunction, (void *)0 );
}
void * theClass::theFunction( void * arg )
{
cout << "this is a test: " << (int )arg << endl;
}
this code was working great! but now i need it to work for multiple derived classes. here's what i want:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class derived1: public theClass
{
public :
derived1( void )
{
theClass::startThread( &derived1::test1, (void *)0 );
}
void * test1( void * arg )
{
cout << "this is derived1!\n" ;
}
};
class derived2: public theClass
{
public :
derived2( void )
{
theClass::startThread( &derived2::test2, (void *)0 );
}
void * test2( void * arg )
{
cout << "this is derived2!\n" ;
}
};
however i'm not sure how to implement my base class "theClass" to work with multiple derived classes (without having static definitions for them hard-coded inside the base class). i'm thinking i can achieve this with templates but i'm at a loss of how to make it work. any help at all would be great!
thanks!
Mar 14, 2009 at 6:52am UTC
You have some nasty typecasting going on. Member functions are tricky.
1 2 3
class Base {
typedef void (Base::*Function)( void * );
};
only matches member functions of Base that have the given return type and parameters. It does not match member functions of classes derived from Base, even if those functions have the correct return type and parameters.
To fix this, you need boost::function and boost::bind.
www.boost.org
typedef boost::function< void ( void * ) > Function;
You can stuff
any function into this as long as it returns void and takes a single void* as parameter. It can be a member function of any class, virtual or not, free function, or even function object.
Last edited on Mar 14, 2009 at 6:53am UTC
Mar 14, 2009 at 3:39pm UTC
thank you very much for your suggestion! i will try it and report back!
Mar 21, 2009 at 7:29pm UTC
after trying different methods i came up with this code:
main.cpp: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include <boost/function.hpp>
#include <iostream>
using namespace std;
typedef boost::function<void * (void *)> func;
struct threadNfo
{
func f;
void * args;
};
class delegateThread
{
public :
virtual pthread_t startThread( func f, void * args )
{
pthread_t th; //thread structure to return to the caller.
threadNfo* tn = new threadNfo();
tn->f = f; //target threaded member-function.
tn->args = args; //parameters to pass.
pthread_create( &th, NULL, doStartThread, (void *)tn ); //invoking the threaded function.
return th;
}
private :
static void * doStartThread( void * ptr )
{
threadNfo* tn = static_cast <threadNfo*>(ptr); //retreiving the thread information.
(tn->f)( tn->args ); //calling the member function, which is now in a seperate thread.
delete tn; //cleaning up.
return 0; //returning a dummy value.
}
};
class test: public delegateThread
{
public :
test( void )
{
startThread( &test::foo, (void *)0 );
cout << _i << endl;
}
void * foo( void * bar )
{
cout << (int )bar << "\n" ;
_i = 1 + (int )bar;
return 0;
}
private :
int _i;
};
int main()
{
test t;
return 0;
}
the code gives no errors however when i try and compile i get a slew of errors from the boost libraries:
$ g++ main.cpp
/usr/include/boost/function/function_template.hpp: In static member function ‘static R boost::detail::function::function_obj_invoker1<FunctionObj, R, T0>::invoke(boost::detail::function::function_buffer&, T0) [with FunctionObj = boost::_mfi::mf1<void*, test, void*>, R = void*, T0 = void*]’:
/usr/include/boost/function/function_template.hpp:368: instantiated from ‘void boost::detail::function::basic_vtable1<R, T0, Allocator>::init(FunctionObj, boost::detail::function::function_obj_tag) [with FunctionObj = boost::_mfi::mf1<void*, test, void*>, R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:298: instantiated from ‘void boost::detail::function::basic_vtable1<R, T0, Allocator>::init(F) [with F = boost::_mfi::mf1<void*, test, void*>, R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:339: instantiated from ‘void boost::detail::function::basic_vtable1<R, T0, Allocator>::init(MemberPtr, boost::detail::function::member_ptr_tag) [with MemberPtr = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:298: instantiated from ‘void boost::detail::function::basic_vtable1<R, T0, Allocator>::init(F) [with F = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:277: instantiated from ‘boost::detail::function::basic_vtable1<R, T0, Allocator>::basic_vtable1(F) [with F = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:655: instantiated from ‘void boost::function1<R, T0, Allocator>::assign_to(Functor) [with Functor = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:513: instantiated from ‘boost::function1<R, T0, Allocator>::function1(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
/usr/include/boost/function/function_template.hpp:753: instantiated from ‘boost::function<R ()(T0), Allocator>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = void* (test::*)(void*), R = void*, T0 = void*, Allocator = std::allocator<void>]’
main.cpp:47: instantiated from here
/usr/include/boost/function/function_template.hpp:134: error: no match for call to ‘(boost::_mfi::mf1<void*, test, void*>) (void*&)’
/usr/include/boost/bind/mem_fn_template.hpp:160: note: candidates are: R boost::_mfi::mf1<R, T, A1>::operator()(T*, A1) const [with R = void*, T = test, A1 = void*]
/usr/include/boost/bind/mem_fn_template.hpp:179: note: R boost::_mfi::mf1<R, T, A1>::operator()(T&, A1) const [with R = void*, T = test, A1 = void*]
i installed boost on my ubuntu 8.10 distro via:
$ apt-get install libboost.*-dev libboost-doc libboost.*1.34.1
i can't make any sense of these error messages but i was wondering if anyone can spot a problem by simply looking at my code.
thanks!
Mar 22, 2009 at 5:45pm UTC
Line 48 needs to be
startThread( boost::bind( &test::foo, this , _1 ), 0 );
Mar 22, 2009 at 10:05pm UTC
thanks for the help jsmith ! everything is working fine now!
i'll try and look into a way to do the binding inside startThread instead of having to bind in the function call.
Topic archived. No new replies allowed.