Passing a template to a thread?

Dec 30, 2009 at 1:54am
Is it possible to pass a template to a thread using the WinAPI?

I'm trying to call _beginthreadex and pointing it to a function which takes a template but it gives me the error

 
'_beginthreadex' : cannot convert parameter 3 from 'unsigned int (__stdcall *)(void *)' to 'unsigned int (__stdcall *)(void *)'


Which to me makes no sense, but I am guessing it throws that error because _beginthreadex is not made to handle functions that accept templates.


Since what I am trying most likely won't ever work... Is there a way to make a global template? At the moment I have a class which contains a member function which accepts a class type as a template. I want to pass this template onto a newly created thread but I can't get around the problem of _beginthreadex. Is there anyway to directly pass a template type/value from one function to another?
Dec 30, 2009 at 2:00am
Show us the code that is failing.
Dec 30, 2009 at 2:09am
From 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
#include <iostream>
#include "Thread.h"

using namespace std;

class Test
{
public:
	Test()
	{
		cout << "\nWOAH\n";
		delete this;
	}
	~Test()
	{
		cout << "\n :( \n";
	}
};


int main()
{

	ThreadThing::Thread.Create<Test>();

	system("pause");

	return 0;
}


From Thread.h

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

#ifndef THREAD_H
#define THREAD_H
#include <windows.h>
#include <iostream>
#include <process.h>
#include <vector>
using namespace std;


class Thread
{
public:
	template<class T>
	void Create()
	{
		HANDLE ThreadID;
		ThreadID = (HANDLE)_beginthreadex(NULL,0,ThreadFunction, this, 0, NULL);
		if (ThreadID != NULL)
		{
			thread_handles.push_back(ThreadID);
		}
		else 
		{
			cout << "error!";
		}
	}

private:
	template<class T>
	static unsigned __stdcall ThreadFunction(void* lparam)
	{
		cout << "\n In Thread\n";
		return static_cast<Thread*>(lparam)->Run();
	}
	template<class T>
	DWORD Run(void)
	{
		cout << "\n In Run";
		new T;
		return 0;
	}
	vector<HANDLE> thread_handles;
};


namespace ThreadThing
{
	Thread Thread;
};



#endif



It was my understanding that templates are kinda inherited, when Create calls ThreadFunction the template is passed on to it, which is then passed onto Run.

EDIT: Well it works if I put the entire thread class under a single template<class T> and remove the others but then you have to create a new Thread object each time you want to make a new thread. I had hoped there was a way to create a single Thread object which could manage any child threads and create new ones.
Last edited on Dec 30, 2009 at 2:28am
Dec 30, 2009 at 3:39am
A few things:

1) Your names aren't ideal. A "Thread" logically sounds like it'd be a singular thread, but your thread class here is actually keeping track of a group of threads. Something like "ThreadManager" or the like would make more sense.

2) Rather than use templates here ... polymorphism would be a better approach. IE, have your individual thread classes (such as 'Test') derive from a common 'ThreadBase' base class.

3) This is bad:

1
2
3
4
5
	Test()
	{
		cout << "\nWOAH\n";
		delete this;     // RED FLAG!
	}


Suicide in a ctor is risky business if you're not careful. I gather this is just a temporary measure and you won't actually have your program work this way when it's done, but this threw up all sorts of red flags in my brain.

4) Another design idea might be to make this class a singleton and not make the user generate an instance of it. ThreadBase (and derived) classes could add themselves to the singleton group in their ctor or something. Just be sure to be carefule and watch out for the static order initialization fiasco.

5) This:

1
2
3
4
namespace ThreadThing
{
	Thread Thread;
};


Are you TRYING to cause confusion / name conflicts?
Dec 30, 2009 at 3:46am
you have to create a new Thread object each time you want to make a new thread
That doesn't make sense to you?

I had hoped there was a way to create a single Thread object which could manage any child threads and create new ones.
What you want is a ThreadManager class, although how it's going to manage Thread<T> with different values of T is beyond me.

What you should do, I think, is change the call to _beginthreadex():
ThreadID = (HANDLE)_beginthreadex(NULL,0,ThreadFunction<T>, this, 0, NULL);
And to Run():
return static_cast<Thread*>(lparam)->Run<T>();
How were you expecting the templates to figure out the values of their parameters?
Dec 30, 2009 at 4:15am
I had been worried more about getting the program to work first and then I would change the names to something more informative.

My idea was to make a single class that could create Threads which would run one or more classes. Each time a new thread is created a new instance of a class would be created inside that thread and the original Thread class, lets call it ThreadManager from now on, would store the handle and any of information about that thread in a vector/map. That way ThreadManager would contain all the information about any child threads created by the program and choose to terminate or suspend them as needed, I had planned on each class having a constructor that would guide the thread, with the class suiciding once it's task was finished, sending a "done" message to the ThreadManager and closing the thread automaticly.

Telling the ThreadManager which class to create in which thread is where the template was supposed to come in, Run() would create a new instance of the class T inside the thread, which would trigger the classes constructor.

It is my first time using templates though so I was unsure as to how they worked... I'll make the changes you suggested tomorrow when I get the chance and see if they fixed the problem.
Topic archived. No new replies allowed.