Threading with inheritance in multiple derived classes

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!
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
thank you very much for your suggestion! i will try it and report back!
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!
Line 48 needs to be

 
startThread( boost::bind( &test::foo, this, _1 ), 0 );

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.