Below I have an int main() and two header files, one of which is a class for creating a thread and another which is a class called object that gets created within the windows_thread class. This really simple exercise should output 99 but instead its 1 (for some unknown reason). I also tried using a pointer to an object made by new which crashed when void call() from the function Thread_no_1( ) to the class object is made, maybe because its none existent. I hope someone could remedy this otherwise I'll just use windows threads in int main().
this is the main.
#include "windows_thread.h"
int main()
{
windows_thread* THREAD = new windows_thread();
THREAD->thread();
delete THREAD;
return 0;
}
this is the windows_thread.h
#include <windows.h>
#include <stdio.h>
#include "object.h"
#define BUF_SIZE 255
class windows_thread
{
object OBJECT;
public:
windows_thread():OBJECT(99)
{
//OBJECT = new object(99);
}
~windows_thread()
{
//delete OBJECT;
}
void thread()
{
std::cout<<"void thread: "<<std::endl;
int Data_Of_Thread_1 = 1; // Data of Thread 1
HANDLE Handle_Of_Thread_1 = 0; // variable to hold handle of Thread 1
HANDLE Array_Of_Thread_Handles[1]; // Aray to store thread handles
// Create thread 1.
Handle_Of_Thread_1 = CreateThread( NULL, 0, Wrap_Thread_no_1, &Data_Of_Thread_1, 0, NULL);
if ( Handle_Of_Thread_1 == NULL) ExitProcess(Data_Of_Thread_1);
// Store Thread handles in Array of Thread Handles as per the requirement of WaitForMultipleObjects()
Array_Of_Thread_Handles[0] = Handle_Of_Thread_1;
// Wait until all threads have terminated.
WaitForMultipleObjects( 1, Array_Of_Thread_Handles, TRUE, INFINITE);
printf("Since All threads executed lets close their handles \n");
// Close all thread handles upon completion.
CloseHandle(Handle_Of_Thread_1);
}
void DisplayMessage (HANDLE hScreen, char *ThreadName, int Data, int Count)
{
TCHAR msgBuf[BUF_SIZE];
size_t cchStringSize;
DWORD dwChars;
// Print message using thread-safe functions.
//StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Executing iteration %02d of %s having data = %02d \n"), Count, ThreadName, Data);
//StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
WriteConsole(hScreen, msgBuf, cchStringSize, &dwChars, NULL);
Sleep(1000);
}
DWORD WINAPI Thread_no_1( )
{
std::cout<<"Thread_no_1: "<<std::endl;
OBJECT.call();
//OBJECT->call();
return 0;
}
static DWORD WINAPI Wrap_Thread_no_1( LPVOID lpParam )
{
std::cout<<"Wrap_Thread_no_1: "<<std::endl;
windows_thread *self = reinterpret_cast<windows_thread*>(lpParam);
self->Thread_no_1();
return 0;
}
};
next is the object.h
#ifndef OBJECT_H
#define OBJECT_H
#include <iostream>
class object
{
private:
int value;
public:
object(int value)
{
std::cout<<"object::constructor: "<<std::endl;
this->value = value;
}
~object(){}
void call()
{
std::cout<<"object::call(): begin"<<std::endl;
std::cout<<value<<std::endl;
std::cout<<"object::call(): end"<<std::endl;
}
};
#endif
This function call:
Handle_Of_Thread_1 = CreateThread(
NULL,
0,
Wrap_Thread_no_1,
&Data_Of_Thread_1, // <== THIS IS A POINTER TO AN int
0,
NULL
);
Passes &Data_Of_Thread_1 (a pointer to an int) to CreateThread(). This is the argument that gets eventually passed to Wrap_Thread_no_1().
Inside that function, you then cast that pointer to a windows_thread* and call a member function through it. This injects Undefined Behavior in your code.
You probably meant to do this instead:
Handle_Of_Thread_1 = CreateThread(NULL, 0, Wrap_Thread_no_1, this, 0, NULL);
// ^^^^
Related
(Note before starting: Although my question is general, my code needs to compile with legacy Visual Studio 2008 MFC application and has to use MFC or win32 synchronization, please avoid answers using ie boost or c++ 11)
I am trying to implement a Thread Safe Pipe (A Queue with a single reader and a single writer), I did the following:
template<class T>
class CMultiThreadPipe {
private:
HANDLE hSemaphore, hTerminateEvent1, hTerminateEvent2;
CRITICAL_SECTION listMutex;
CList<T*, T*> list;
public:
CMultiThreadPipe() {
InitializeCriticalSection(&listMutex);
hSemaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
hTerminateEvent1 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
hTerminateEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}
// pdata must be allocated with new. The dequeueing thread will delete it
void Enqueue(T* pdata) {
EnterCriticalSection(&listMutex);
list.AddHead(pdata);
LeaveCriticalSection(&listMutex);
ReleaseSemaphore(hSemaphore, 1, NULL);
}
// if Dequeue returns null it means the pipe was destroyed and no further queue method calls are legal
// Dequeue caller is responsible to delete the returned instance
T* Dequeue()
{
HANDLE handles[] = { hTerminateEvent1, hSemaphore };
DWORD waitRes = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (waitRes==WAIT_OBJECT_0) {
SetEvent(hTerminateEvent2);
return NULL; // terminated
}
EnterCriticalSection(&listMutex);
T* elem = list.RemoveTail();
LeaveCriticalSection(&listMutex);
return elem; // handler must delete item
}
void Destroy() {
SetEvent(hTerminateEvent1);
WaitForSingleObject(hTerminateEvent2, INFINITE);
EnterCriticalSection(&listMutex);
POSITION pos = list.GetHeadPosition();
for (int i = 0; i < list.GetCount(); i++) delete list.GetNext(pos);
LeaveCriticalSection(&listMutex);
DeleteCriticalSection(&listMutex);
CloseHandle(hSemaphore);
}
~CMultiThreadPipe() {
Destroy();
}
};
The code is used like this:
class QueueData {
public:
QueueData(int i) : m_data(i) {};
int m_data;
};
UINT DequeueThreadProc(LPVOID dummy);
CMultiThreadedPipe<QueueData>* pPipe = NULL;
void main() {
pPipe = new CMultiThreadedPipe<QueueData>();
start new thread running DequeueThreadProc
int counter=0;
for (int counter=0; counter<10; counter++)
{
pPipe->Enqueue(new QueueData(counter));
Sleep(300);
}
delete pPipe;
}
UINT DequeueThreadProc(LPVOID ignore)
{
QueueData* queueData;
while ((queueData = pPipe->Dequeue()) != NULL) {
delete queueData;
Sleep(1000);
};
return 0;
}
The issue I have is with termination, in the above implementation, when the pipe is destroyed (always by the enqueing thread) it is waiting for the dequeing thread to know that it terminated before deleting the queue. It has to do that to prevent a situation where the dequeing thread tries to dequeue after the pipe is destroyed.
If the dequeing thread does not keep calling dequeue the first thread will hang in the destructor, also if the dequeing thread waits a long time between calls to dequeue the destructor of the first thread will get stuck there accordingly.
I read various posts about it none mentions safe destruction. Any help appreciated !
for safe destruction object, which accessed from multiple threads you need use reference counting on it. before pass object pointer to new thread - you increment reference on object. when thread no more using object, or if create thread fail, you decrement reference count. when last reference on object released - you can safe call destructor for object. and you not need here wait for any threads.
also for implement such queue - in windows exist special object - named I/O Completion Ports in user space (in kernel space in know as KQUEUE). with this object - implementation will be more efficient and simply - you not need manage self list (CList in your code), synchronize access to it - all this will be done in kernel space for you (PostQueuedCompletionStatus -> KeInsertQueue, GetQueuedCompletionStatus -> KeRemoveQueue). you need create only iocp, (kqueue) object.
class CMultiThreadPipe {
public:
class __declspec(novtable) QueueData {
public:
virtual void ProcessItem() = 0;
virtual ~QueueData()
{
DbgPrint("%x: %s<%p>\n", GetCurrentThreadId(), __FUNCTION__, this);
}
QueueData()
{
DbgPrint("%x: %s<%p>\n", GetCurrentThreadId(), __FUNCTION__, this);
}
};
private:
HANDLE _hIOCP;
LONG _dwRef;
ULONG _nThreads;
void DequeueThreadProc()
{
ULONG NumberOfBytesTransferred;
QueueData* pData;
OVERLAPPED* pOverlapped;
while (GetQueuedCompletionStatus(_hIOCP,
&NumberOfBytesTransferred,
(ULONG_PTR*)&pData,
&pOverlapped, INFINITE))
{
if (pData)
{
pData->ProcessItem();
}
else
{
break;
}
}
Release();
}
__declspec(noreturn) static DWORD CALLBACK _DequeueThreadProc(PVOID pThis)
{
reinterpret_cast<CMultiThreadPipe*>(pThis)->DequeueThreadProc();
FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);
}
~CMultiThreadPipe()
{
if (_hIOCP)
{
CloseHandle(_hIOCP);
}
}
public:
CMultiThreadPipe() : _dwRef(1), _hIOCP(0)
{
}
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef))
{
delete this;
}
}
ULONG Create(DWORD NumberOfDequeueThreads)
{
if (_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, NumberOfDequeueThreads))
{
ULONG n = 0;
do
{
HMODULE hModule;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCWSTR)_DequeueThreadProc, &hModule))
{
AddRef();
if (HANDLE hThread = CreateThread(0, 0, _DequeueThreadProc, this, 0, 0))
{
CloseHandle(hThread);
n++;
}
else
{
Release();
FreeLibrary(hModule);
}
}
} while (--NumberOfDequeueThreads);
_nThreads = n;
return n ? NOERROR : ERROR_GEN_FAILURE;
}
return GetLastError();
}
ULONG Enqueue(QueueData* pData)
{
return PostQueuedCompletionStatus(_hIOCP, 0, (ULONG_PTR)pData, 0) ? NOERROR : GetLastError();
}
void Destroy()
{
if (ULONG n = _nThreads)
{
do
{
PostQueuedCompletionStatus(_hIOCP, 0, 0, 0);
} while (--n);
}
}
};
and usage:
class QueueData : public CMultiThreadPipe::QueueData
{
int m_data;
virtual void ProcessItem()
{
DbgPrint("%x: %s<%p>(%u)\n", GetCurrentThreadId(), __FUNCTION__, this, m_data);
delete this;
}
public:
QueueData(int i) : m_data(i) {};
};
void testQueue()
{
if (CMultiThreadPipe* pPipe = new CMultiThreadPipe)
{
if (pPipe->Create(8) == NOERROR)
{
int n = 64;
do
{
if (QueueData* pData = new QueueData(n))
{
if (pPipe->Enqueue(pData))
{
delete pData;
}
}
} while (--n);
pPipe->Destroy();
}
pPipe->Release();
}
}
note with such CMultiThreadPipe implementations - you not need wait when working threads exit. even if your code inside dll and you unload dll - you not need wait. every thread have own reference for object and module. and release it on exit
I have an array of objects and want each one to call a member function in a separate thread (so they run concurrently). I'm using _beginthreadex and can get it to work fine for a standard function but can't figure out the syntax to pass the member function to the _beginthreadex call. Here's an example of what I'm doing (the block of code after the second comment does not compile):
#include <Windows.h>
#include <process.h>
#include <stdio.h>
unsigned __stdcall mythread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
return 0;
}
class myClass {
public:
unsigned __stdcall myClass::myThread(void* data);
};
unsigned __stdcall myClass::myThread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
return(0);
}
int main(int argc, char* argv[]) {
int i, numThreads = 5;
// this works
HANDLE *myHandle = new HANDLE[numThreads];
for(i=0;i<numThreads;i++) myHandle[i] = (HANDLE)_beginthreadex(0, 0, &mythread, 0, 0, 0);
WaitForMultipleObjects(numThreads, myHandle, true, INFINITE);
for(i=0;i<numThreads;i++) CloseHandle(myHandle[i]);
getchar();
delete myHandle;
// this does not compile - not sure of syntax to call myObject[i].myThread in _beginthreadex
HANDLE *myHandle2 = new HANDLE[numThreads];
myClass *myObject = new myClass[numThreads];
for(i=0;i<numThreads;i++) myHandle2[i] = (HANDLE)_beginthreadex(0, 0, &myObject[i].myThread, 0, 0, 0);
WaitForMultipleObjects(numThreads, myHandle2, true, INFINITE);
for(i=0;i<numThreads;i++) CloseHandle(myHandle2[i]);
getchar();
delete myObject;
delete myHandle2;
return 0;
}
Thanks in advance for any help!
rgames
You cannot get address of member fuinction using
&myObject[i].myThread
correct way is like this
&myClass::myThread
In C++ functions and member functions have different signature like
/* pointer for this function would have type void(*)(int, float) */
void foo(int, float) { /* ... */ }
class A {
public:
/* pointer for this function would have type void(A::*)(int, float) */
void foo(int, float) { /* ... */ }
};
they are have different type even they both return void and take int and float.
As you can see in msdn the _beginthread function takes function as
unsigned (__stdcall *)( void * )
but you are trying to pass
unsigned (__stdcall myClass::*)( void* )
So to correct your code you can do:
Method 1: you need to write another function, something like
unsigned __stdcall mymemberthread(void* data) {
if (data != NULL) {
myClass* m = (myClass*)data;
m->myThread(m + 1);
}
return 0;
}
And create thread like
(HANDLE)_beginthreadex(0, 0, &mymemberthread, &myObject[i], 0, 0);
Method 2: make function myClass::myThread static
class myClass {
public:
static unsigned __stdcall myThread(void* data);
};
unsigned __stdcall myClass::myThread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
if (data != NULL) {
myClass* m = (myClass*)data;
m->myThread(m + 1);
}
return(0);
}
...
(HANDLE)_beginthreadex(0, 0, &myClass::myThread, &myObject[i], 0, 0);
Method 3: if this is acceptabe use STL and std::thread, this will make you code more generic.
I want to know how to pass a structure to a thread. I've written an example application where I declare a structure in main and try to pass it to the thread.
Here's my code:
DWORD WINAPI Name1(LPVOID lparam)
{
data x;
x.name[15]="Sarah";
x.DOB="19/10/2007";
fputs(stdout,name,15);
fputs(stdout,DOB,15);
return 0;
}
int main()
{
struct data
{
char name[15];
char DOB[15];
};
HANDLE thread2;
DWORD threadID2;
thread2= CreateThread(NULL,0,Name1,(LPVOID *)data,0,&threadID2);
if(thread2==NULL)
{
cout<<"Couldn't Create Thread:("<<endl;
exit(0);
}
return 0;
}
Unfortunately, I am not getting the hang of passing a structure to a thread :( I would really appreciate it if somebody helped me out.
I tried to change the datatype of the structure to pass it, but, I guess I don't know how to do it.
You are passing a local variable to the thread startup function. Once the variable goes out of scope it will be destroyed. This means it may not exist when the new thread tries to access it. You should either pass by value for integral types or allocate the object in dynamic storage (the heap).
Once the new thread has the pointer to the object it should probably be responsible for destroying it as well. That all depends on how you want to assign and manager ownership of the object.
struct Foo
{
char name[15];
char DOB[15];
};
void Start()
{
Foo *someObject = new Foo();
CreateThread(NULL, 0, threadFunc, (LPVOID *)someObject, 0, &threadID2);
}
DWORD WINAPI threadFunc(void *v)
{
Foo *someObject = static_cast<Foo*>(v);
delete someObject;
return 0;
}
If you want to pass a struct to a thread, you've to get that struct on the heap and not on the stack and pass its address to the thread.
I also fixed a few mistakes... Like string copy, and so on...
I didn't use any typedef, as it appears you're using C++.
struct data{
char name[15];
char DOB[15];
};
DWORD WINAPI Name1(LPVOID lparam)
{
data *x = (data*)lparam;
strcpy(x->name, "Sarah");
strcpy(x->DOB, "19/10/2007");
fputs(stdout, x->name, 15);
fputs(stdout, x->DOB, 15);
HeapFree(GetProcessHeap(), 0, x);
return 0;
}
int main()
{
HANDLE thread2;
DWORD threadID2;
data * x;
x = HeapAlloc(GetProcessHeap(), 0, sizeof(data));
thread2= CreateThread(NULL, 0, Name1, (LPVOID)x, 0, &threadID2);
if(thread2==NULL)
{
cout << "Couldn't Create Thread:(" << endl;
exit(0);
}
return 0;
}
I'm trying to create 12 new instances of a class and run each of them it's a own thread, but they seam to share the same data.
all 12 instances are on the same X and Y position, but they each should move on a random direction.
as you can see in the code, i tried various apraoches and i can't find out why.
what am i doing wrong here?
p.s. yes ... i know there are still some unused variables.
p.s.s i have looked at many places and also here before i posted the question
enemy.cpp
#include "enemy.h"
#include <time.h>
#include <windows.h>
FILE* pEnemyFile = fopen ("enemylog.txt","w");
Enemy::Enemy(const MouseServer& mServer, int& lastMousePosX, int& lastMousePosY, int& winSizeX, int& winSizeY )
:mouseServer(mServer),
lastMouseX( ( lastMousePosX ) ? lastMousePosX : 0 ), // evaluate if we get the reference
lastMouseY( ( lastMousePosY ) ? lastMousePosY : 0 ),
myPositionX(0),
myPositionY(0),
winSizeX(winSizeX),
winSizeY(winSizeY),
x(0),
y(0)
{
// original source:
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx
// Allocate memory for thread data.
EDATA threadEnemyData = (EDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(enemyData));
// http://www.codeproject.com/Articles/14746/Multithreading-Tutorial
// http://www.codeguru.com/cpp/w-d/dislog/win32/article.php/c9823/Win32-Thread-Synchronization-Part-I-Overview.htm
// usefull information
// http://msdn.microsoft.com/en-us/library/z3x8b09y(v=vs.100).aspx
if( threadEnemyData == NULL )
{
//If the array allocation fails, the system is out of memory
//so there is no point in trying to print an error message.
//Just terminate execution.
ExitProcess(2);
}
threadEnemyData->X = 0;
threadEnemyData->Y = 0;
this->hThread = CreateThread(
NULL,
0,
this->MyThreadFunction,
this,
/*threadEnemyData,*/
0,
&this->dwThreadID
);
// Check the return value for success.
// If CreateThread fails, terminate execution.
// This will automatically clean up threads and memory.
if (this->hThread== NULL)
{
ErrorHandler(TEXT("CreateThread"));
ExitProcess(3);
}
//End of main thread creation loop.
}
Enemy::~Enemy()
{
// Wait until all threads have terminated.
WaitForSingleObject(this->hThread,INFINITE);
// Close all thread handles and free memory allocations.
this->hDefaultProcessHeap = GetProcessHeap();
if (this->hDefaultProcessHeap == NULL) {
}
CloseHandle(this->hThread);
//if(threadEnemyData != NULL)
//{
// HeapFree(GetProcessHeap(), 0, threadEnemyData);
// hThread = NULL; // Ensure address is not reused.
//}
// close debug file
fclose (pEnemyFile);
}
void Enemy::Draw(D3DGraphics& gfx)
{
gfx.PutPixel(this->x + 0,this->y,255,255,255);
gfx.PutPixel(this->x + 1,this->y,255,255,255);
gfx.PutPixel(this->x + 2,this->y,255,255,255);
gfx.PutPixel(this->x + 3,this->y,255,255,255);
gfx.PutPixel(this->x + 4,this->y,255,255,255);
gfx.PutPixel(this->x + 5,this->y,255,255,255);
gfx.PutPixel(this->x + 6,this->y,255,255,255);
gfx.PutPixel(this->x + 7,this->y,255,255,255);
}
// read
// http://www.tek-tips.com/viewthread.cfm?qid=1068278
DWORD WINAPI Enemy::MyThreadFunction( void* param )
{
Enemy* self = (Enemy*) param;
////self-> // <-- "this"
return self->NewThread();
}
/* initialize random seed: */
// the itelligence loop of your enemy/object
DWORD Enemy::NewThread()
{
do
{
srand ( time(NULL) );
/* generate random number: */
//self->x += rand() % 4;
//self->y += rand() % 4;
this->x += rand() % 4;
this->y += rand() % 4;
// debug stuff
char buffer[ 64 ];
sprintf_s(buffer, "enemy: x: %d Y: %d id: %d\n", (char)this->x, (char)this->y, (char)this->dwThreadID);
fputs (buffer,pEnemyFile);
// allow processor time to other threads
Sleep(100);
}while(true); // endles loop
}
void Enemy::ErrorHandler(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code.
this->dw = GetLastError();
// todo
}
enemy.h
#pragma once
#include "timer.h"
#include "D3DGraphics.h"
#include "D3DGraphics.h"
#include "Mouse.h"
/////// thread stuf
#include <tchar.h>
#include <strsafe.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
class Enemy
{
public:
Enemy();
Enemy(const MouseServer& mServer, int& lastMousePos, int& lastMousePosY, int& winSizeX, int& winSizeY);
~Enemy();
static DWORD WINAPI MyThreadFunction( LPVOID lpParam );
DWORD Enemy::NewThread();
void ErrorHandler(LPTSTR lpszFunction);
void lookingForFood();
void Draw(D3DGraphics& gfx);
int Enemy::correctX(int xParam);
int Enemy::correctY(int yParam);
private:
int myPositionX;
int myPositionY;
int lastMouseX;
int lastMouseY;
int winSizeX;
int winSizeY;
//int moveToX; // todo
//int moveToY;
int x;
int y;
// threading stuff
typedef struct ENEMYDATA // don't forget "typedef "
{
int X;
int Y; // test
} enemyData, *EDATA;
// Cast the parameter to the correct data type.
// The pointer is known to be valid because
// it was checked for NULL before the thread was created.
static Enemy* self;
HANDLE hThread;
DWORD dwThreadID;
HANDLE hDefaultProcessHeap;
DWORD dw; // error message
EDATA* threadEnemyData;
MouseClient mouseServer;
//D3DGraphics& grafix;
Timer timer;
};
It's commented out in your thread proc, but looks like you were on the right track:
srand ( time(NULL) );
It didn't work for you because all the threads start so fast that they end up with time(NULL) returning the same value for each thread. This means they're all using the same random sequence. Try seeding rand with the thread ID (or some other source that's unique per thread) and you should see unique pseudorandom number sequences.
I wrote some test code like this which compiled and worked fine...
void threadtest()
{
HANDLE hThrd;
DWORD threadId;
int i;
for (i = 0;i < 5;i++)
{
hThrd = CreateThread(
NULL,
0,
ThreadFunc,
(LPVOID)i,
0,
&threadId );
}
// more stuff
}
DWORD WINAPI ThreadFunc(LPVOID n)
{
// stuff
return 0;
}
Then I wanted to modify the code to put the ThreadFunc inside a class and then declare an array of those classes. I thought the code should look like this:
class thread_type
{
public:
DWORD WINAPI ThreadFunc(LPVOID n)
{
// stuff
return 0;
}
};
void threadtest()
{
HANDLE hThrd;
DWORD threadId;
int i;
thread_type *slave;
slave = new thread_type[5];
for (i = 0;i < 5;i++)
{
hThrd = CreateThread(
NULL,
0,
slave[i].ThreadFunc,
(LPVOID)i,
0,
&threadId );
}
// more stuff
}
Unfortunately the compiler complains about the line slave[i].ThreadFunc, I think I may need some special casting but all the permutations I try involving "::" and "&" seem to fail (I'm quite new to C++). The real code has some additional complications which I haven't included for clarity, but I think they are irrelevant.
First problem with the code, that the test class is not descendant of the thread_type. Somehow you need to specify the base class.
Second is, if you are passing function pointer, that shouldn't be thiscall type. The solution is typically this:
struct thread
{
virtual void
run() = 0;
static thread_func(void* param)
{
thread* pThread = (thread*)param;
thread->run();
}
}
struct worker : public thread
{
void
run()
{
(.. code for the thread...)
}
}
void threadtest()
{
HANDLE hThrd;
DWORD threadId;
int i;
thread *slave;
slave = new thread_type[5];
slave[0] = new worker;
slave[1] = new worker;
slave[2] = new worker;
slave[3] = new worker;
slave[4] = new worker;
for (i = 0;i < 5;i++)
{
hThrd = CreateThread(
NULL,
0,
&thread::thread_func,
(LPVOID)slave[i],
0,
&threadId );
}
// more stuff
}
Note that this could is just a reflection, I couldn't compile now, because I don't have here anything to do so, but the logic should be like this.
The following explains the difference between a pointer to a function and a pointer to a member function C++ FAQ Lite. See section 33.2 which explains why what you are doing is a bad idea.