Click here to Skip to main content
15,891,846 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
Hi, I have a class that has a static method as a threads entry point. A 'this' pointer is passed into the static method in order that the class' member function for the thread can then be called. Later, this thread starts another thread which is still within the same class. I have tried to start this thread in the same way, and the thread starts fine but it doesn't have access to any member variables that were set before. Is it possible to do what I am trying to do? Or should there only be one thread per class, in which case this problem would not arise?

As I have had such a huge amount of response and helpful suggestions, I decided to modify my original question by adding some code to make the situation clearer. However, in doing so I spotted my (very dumb) mistake. I'm sure it will be obvious to you all but I have commented it in capitals!!! I'm very grateful for the very good points you have all made as they have certainly taught me a few things, and if anyone can see any flaws with my method then I'd be very pleased to hear and learn. I think ultimately I should probably have the second thread in another class in order to separate the functionalities. But at least I know that it is possible to do what was trying to do.

C++
//constructor
CardThread::CardThread(CardStatus* pCardStatus)
{
	m_pCardStatus = pCardStatus;
}
//destructor - this never got called when I had a breakpoint in, so the reason for my problem is not because the object is destroyed before the second thread starts
CardThread::~CardThread(void)
{
	int i = 1;
}
//the thread entry point - this method is declared in the header as 'static'
DWORD WINAPI CardThread::CreateCardThread(void* pThis)
{
	CardThread* pCardThread = (CardThread*)pThis;
    
	pCardThread->StartCardThread();

	return 0;
}

bool CardThread::StartCardThread()
{
	//Create a DataWriter thread
	DWORD dwDataWriterThreadID;
        //HERE IS MY MISTAKE!!! '(void*)0 should be '(void*)this' !!!		
	HANDLE hDataWriterThread = CreateThread(NULL, NULL, CreateDataWriterThread, (void*)0, NULL,dwDataWriterThreadID);
	//at this point, m_pCardCtrl is valid
        return true;
}

//this is the entry point for the second thread - it is declared as static in the header
DWORD WINAPI CardThread::CreateDataWriterThread(void* pThis)//(LPVOID iValue)
{
        //now m_pCardCtrl is not valid
	CardThread* pCardThread = (CardThread*)pThis;
	pCardThread->DataWriterThread();
	return 0;
}
int CardThread::DataWriterThread()
{
	//this is where it all goes wrong - m_pCardCtrl is still not valid even though this is a non-static
        //member function
	m_pCardCtrl->AllocBulkWriteBuffers();
	
	return 0;
}
Posted
Updated 9-Mar-12 11:51am
v5
Comments
nv3 9-Mar-12 11:15am    
Does the second thread have its own instance of that class or are the two threads operating on the same class object? In the latter case you would need synchronization mechanism, as Albert has already pointed out. If you have one class object per thread, everything should be fine and easy.

Now, why your second thread doesn't see its class object and the member contains is still the question. My first guess would be that at the moment your second thread starts to run, its class object is already gone. Set a breakpoint in the static thread function and the destructor of your thread class and you will quickly see what's going on. Could it be that your first thread creates the second one, then terminates and deletes his thread object, which happens to be also the second thread's object?
Sergey Alexandrovich Kryukov 9-Mar-12 11:47am    
There is a very good idea in this question. I actually answered and explained what to do with synchronization and other issues. Too bad with C++ it's more difficult than with .NET, but this is a good occasion to discuss all that.

Please see my answer.
--SA
nv3 9-Mar-12 13:51pm    
No doubt that this is an interesting question. When she-programmer wrote that a 'this' pointer is passed into the static member function, I was assuming that the this pointer is passed as void* argument to the _beginthread and in the static function then recast into a class object pointer. So I think, up to this point everything happened the normal way. But perhaps my guess was wrong. Your answer layed out things nicely so that I hope that she-programmer can solve her or his problem now. Thanks SA.
Sergey Alexandrovich Kryukov 9-Mar-12 11:40am    
Despite the criticism by Albert and your confusion about instance vs. static methods, I voted 4 for this question this time (I very rarely vote that high for CodeProject questions). You are raising extremely important problem and actually thinking in right direction.

I hope my answer will help you to solve your problems.
--SA
Albert Holguin 9-Mar-12 18:20pm    
You're making a thread that just starts another thread? ..what for? There's no point in that and creating threads takes up quite a bit of time (relatively).

Why do you have threads accessing members of a class that's not in that thread? I'm not entirely sure what you're trying to accomplish, but it doesn't sound thread safe at all. When you start a thread, he shouldn't have access to any variables outside of himself UNLESS they are protected by a locking mechanism (mutex, critical section, etc.). Otherwise, a thread needs to get passed whatever variables he needs to execute using a structure that is passed when it is created.

she-programmer wrote:
Or should there only be one thread per class, in which case this problem would not arise?

No, classes and threads have little to do with one another. A class can spawn multiple threads (IF NECESSARY) and a thread can use multiple classes to execute its work. Multiple threads shouldn't be accessing the same variables without protection (locking mechanisms, synchronization)! ...otherwise you end up with race conditions!
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 9-Mar-12 11:38am    
No Albert, the idea is very good. The only problem is this: it is very easy to accomplish in .NET (where using the instance (non-static) method should be a dominating paradigm), but not so easy in C++. Unfortunately, OP confused static and instance methods.

Of course, you are right with your concerns, but these problems are very nicely and elegantly solved using a thread wrapper.

Please see my answer to get an idea on what do I mean.
--SA
You certainly can do what you want and you thinking is very good, but you mixed up things with the opposites.

The pointer "this" is only passed the the instance (non-static) method, and not passed to the static method. Things are just the opposite. This is the exact essential difference between static and instance methods.

Now, the problem with C++ is: _beginthread and _beginthreadex expect a pointer to a static function (unlike .NET where you can use either instance of static method in the thread constructor). Of course you should use instance method! But how? You can pass this as an additional parameter using _beginthreadex. This work-around is well explained in this article:
http://www.computersciencelab.com/MultithreadingTut1.htm[^].

Locate the code sample with the comment "arg list holding the "this" pointer". It shows how to pass "this" and use it int the thread function.

That said, it is very good to use a thread through a thread wrapper class implementing the thread method. In this case, you can exchange data between the wrapped thread and other threads at any time (not just at start), with proper synchronization, of course. I feel that you almost came to right solution, but mixed up thing by some reason. Not to worry.

Please also see how the code of the wrapper class could look and be used from my past answers:
How to pass ref parameter to the thread[^],
change paramters of thread (producer) after it started[^].

I apologize that the code in C# (where you can really use an instance method), not in C++, but the rest is very similar, at least the idea.

[EDIT]

I'm also asking my colleagues to contribute to answering this question. I would expect that such C++ thread wrapper class already exists in the form of ready-to-use base class or template class, which could be derived in a purely object-oriented manner with abstract or pseudo-abstract thread method to be overridden. I hope such thing exists in some of the C++ libraries which I don't remember or don't know. Let's see.

—SA
 
Share this answer
 
v2
Comments
Nelek 9-Mar-12 13:01pm    
Nice answer. 5
Sergey Alexandrovich Kryukov 9-Mar-12 20:16pm    
Thank you, Nelek.
--SA
Albert Holguin 9-Mar-12 13:02pm    
You mean like using CWinThread? ...Like I said in my solution, I'm a little confused as to what the OP is trying to accomplish, she would have to clarify or share some code.
Sergey Alexandrovich Kryukov 9-Mar-12 20:19pm    
Not exactly. That is specialized "Win" UI thread related to pumping messages, etc; I mean general purpose thread like my .NET ThreadWrapper...
--SA
You'll find an example of the design suggested by SAKryukov in my article:
Integrating ACE and ATL[^] - and the article also illustrates interaction between threads.

Best regards
Espen Harlinn
 
Share this answer
 
Comments
Jackie Lloyd 10-Mar-12 7:56am    
Thankyou,I will have a read.
Espen Harlinn 11-Mar-12 5:06am    
I hope you'll find it of some use, It was mostly intended as an illustration of how to integrate ACE with ATL :-D
Sergey Alexandrovich Kryukov 10-Mar-12 22:55pm    
Thank you for the reply and this reference; this is like something I expected. My 5.
--SA
Espen Harlinn 11-Mar-12 5:04am    
Thanks Sergey :-D

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900