Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

need help with parameter 3 of CreateThread(...) 2

Status
Not open for further replies.

ADoozer

Programmer
Dec 15, 2002
3,487
AU
back again with yet another question (this visual C business is rather odd)

ok so when i create a thread using

Code:
hThread=CreateThread(NULL,0,NewThread,0,0,&dwThreadID));

the NewThread function usually looks like this

Code:
DWORD _stdcall NewThread(void *param)
{
    ....some code....
    return 0;
}

however if i create a thread from within a class

Code:
SomeClass::SomeClass()
{
    ....code....
    hThread=CreateThread(NULL,0,SomeClass::NewThread,0,0,&dwThreadID));
}

now to keep the NewThread associated with the class i tried

Code:
DWORD _stdcall SomeClass::NewThread(void *param)
{
    ....do stuff here....
    return 0;
}

however using

Code:
hThread=CreateThread(NULL,0,SomeClass::NewThread,0,0,&dwThreadID));

causes errors. (cannot convert parameter 3 from unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)

q: is what im trying even possible?

any help greatly appreciated.

(PS. the code works in a console app, but im trying to write it into a class)

If somethings hard to do, its not worth doing - Homer Simpson
 
You need a static function which then invokes a member function of your class. The instance of the class can be passed as a parameter in the invokation.
Code:
static DWORD _stdcall SomeClass::NewThread(void *param)
{
   SomeClass* self = (SomeClass*) param;
   return self->NewThread ();
}

SomeClass::SomeClass()
{
    ....code....
    hThread=CreateThread (NULL, 0, SomeClass::NewThread, [b]this[/b], 0, &dwThreadID));
}

// This is called from the static function and has no parameters
DWORD SomeClass::NewThread ()
{
   ... code...
   return whatever;
}


};
 
o dear.. guess i need to hit the books.

i dont follow that at all.

and when i try and compile it i get 2 new errors


error C2724: 'NewThread' : 'static' should not be used on member functions defined at file scope
error C2511: 'NewThread' : overloaded member function 'unsigned long (void *)' not found in 'SomeClass'
error C2664: 'NewThread' : cannot convert parameter 3 from 'unsigned long (void)' to 'unsigned long (__stdcall *)(void *)'
None of the functions with this name in scope match the target type
thnx for the input


If somethings hard to do, its not worth doing - Homer Simpson
 
You also need to add it to the header definition
Code:
class SomeClass
{
...
   static DWORD _stdcall NewThread (void*);
...
};
 
yeah i did that

.h file

Code:
// MultiplayerIPBan.h: interface for the MultiplayerIPBan class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MULTIPLAYERIPBAN_H__B50C0BC7_679A_4845_99DB_7360B5F9E249__INCLUDED_)
#define AFX_MULTIPLAYERIPBAN_H__B50C0BC7_679A_4845_99DB_7360B5F9E249__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#pragma comment(lib, "ws2_32.lib")

#include <winsock2.h>
#include <stdio.h>

#define SIO_RCVALL	(0x98000001)

class MultiplayerIPBan  
{
public:
	static DWORD _stdcall SniffThread();
	BOOL	SnifferRunning;

	MultiplayerIPBan();
	virtual ~MultiplayerIPBan();

private:
	static SOCKET sock;
	DWORD dwSniffThreadID;
	HANDLE hSniffThread;
};

#endif // !defined(AFX_MULTIPLAYERIPBAN_H__B50C0BC7_679A_4845_99DB_7360B5F9E249__INCLUDED_)

.cpp file
Code:
// MultiplayerIPBan.cpp: implementation of the MultiplayerIPBan class.
//
//////////////////////////////////////////////////////////////////////

#include "MultiplayerIPBan.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
static DWORD _stdcall MultiplayerIPBan::SniffThread(void *param)
{
   MultiplayerIPBan* self = (MultiplayerIPBan*) param;
   return self->SniffThread ();
}

DWORD MultiplayerIPBan::SniffThread ()
{
   return 0;
}


MultiplayerIPBan::MultiplayerIPBan()
{
        ...bunch of stuff....

	if(NULL==(hSniffThread=CreateThread(NULL,0,MultiplayerIPBan::SniffThread,this,0,&dwSniffThreadID)))
	{
		SnifferRunning=FALSE;
		return;
	}

	SetThreadPriority(hSniffThread,THREAD_PRIORITY_HIGHEST);
}

MultiplayerIPBan::~MultiplayerIPBan()
{
	SnifferRunning=FALSE;
	TerminateThread(hSniffThread,dwSniffThreadID);
	closesocket(sock);
	WSACleanup();
}

ill have another look in the morning... (im still not 100% on what your code snippet does)

If somethings hard to do, its not worth doing - Homer Simpson
 
Code:
class someClass
{
   // constructor
   someClass();

   // a static member function for thread
   static unsigned long WINAPI myMemberThread(void* lParam);

   // a HANDLE class member for the thread
   HANDLE   myMemberHandle;
};

in the .cpp file you can start the thread from anywhere in your class such as the constructor - the thread will exist for as long as object...

Code:
// eg. start the thread in the constructor
someClass::someClass()
{
   auto unsigned long  tid=0;

   // kick start the member thread
   myMemberHandle=::CreateThread(0L,0,someClass::myMemberThread,this,0,&tid);
}

// the thread member function itself
unsigned long WINAPI someClass::myMemberThread(void* lParam)
{
     while(lParam)
     {
          // do something here!

           // allow processor time to other threads
          ::Sleep(50);
     }
}
 
aha... that fixed it.

however now i have yet another problem when i try and reference private variables.

error C2597: illegal reference to data member 'Class::DataMember' in a static member function

i cant make the variables static, because (as i understand it) then it limits scope to the header file. and if i make them global.. then hell whats the point of OOPing it anyway.

i also cant use any of my public access functions without getting

error C2352: 'Class::Function' : illegal call of non-static member function

there must be an easier way to do this surely??

again all help much appreciated.


If somethings hard to do, its not worth doing - Homer Simpson
 
There's a couple of ways around this. In the earlier example, notice how we pass in the "this" variable as parameter 4 to ::CreateThread() - you can reference that object within the thread by dereferencing the lParam variable like so:

Code:
unsigned long WINAPI someClass::myMemberThread(void* lParam)
{
     auto someClass* myClass=(someClass*)lParam;

     // access a member of this object
     someClass->doSomething;
}

*or*

You can create a "static" someClass object as a member of the class itself...

Code:
class someClass
{
    // a static someClass member
    static someClass*     mThis;
};

and then access members and member functions within the thread using the "mThis" instead of lParam, eg:

Code:
unsigned long WINAPI someClass::myMemberThread(void* lParam)
{
     mThis->doSomething;
}

If you go with the latter, *don't* forget to initialize the static member at the head of your .cpp file like so:

Code:
someClass*   someClass::mThis=0L;

// rest of .cpp code here.....
 
Passing "this" to CreateThread is generally considered a very bad idea. I learned why the hard way. Find another way to accomplish what you need. The best idea is generally to make a struct that holds everything you need, dynamically allocate it in the function that creates the thread, then delete it right before the thread finishes. You may also need to use mutexes. You may also use PostMessage if it helps, as this is a thread safe function.
 
buzznick, thanks again. ill give it a try tomorrow.

timmay3141, could you comment a little more on your "learning the hard way" and why this method isnt advised, and ways to limit the problems it may cause

thanx all

If somethings hard to do, its not worth doing - Homer Simpson
 
Well, by definition another thread will be executing more or less simultaneously with your main thread. This can lead to a conflict where the two threads are trying to access the same variables at the same time. It can also lead to some nasty debugging problems. In my particular instance I had program crashes because of this kind of thing. If you are doing something very simple, you might be able to get away with doing it that way, but you should try to avoid it. Like I said, the best way to do this is create a struct with all the values the thread will need and pass that to the struct instead. If this thread is going to need to run and communicate with the first thread in any significant way, you should use PostMessage if your primary thread is running with a Window or use mutexes to ensure that it is thread-safe.
 
originaly the code is in a seperate program, and communication was via a named pipe.

there is no real cross thread communication. (worker thread occasionaly writes to a text stream, and the calling thread reads it)

thanks for the info. i will bear it in mind

If somethings hard to do, its not worth doing - Homer Simpson
 
Hi ADoozer,

If you're ever worried about two threads accessing something at the same time, you should use a CRITICAL_SECTION for your thread. This prevents one thread from accessing the data in the 2nd thread until the first thread let's go of it.

Code:
CRITICAL_SECTION    myCriticalSection;

::InitializeCriticalSection(&myCriticalSection);

Then, in the thread itself...

Code:
unsigned long WINAPI myThread(void* lParam)
{
    // prevent dual thread access from here
    ::EnterCriticalSection(&myCriticalSection);

    doSomething();

    // relinquish access to critical section
    ::LeaveCriticalSection(&myCriticalSection);
    return (0);
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top