Jump to content
  • Advertisement
Sign in to follow this  
shurcool

RAII doesn't apply here?

This topic is 3667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've been using the RAII pattern for my Thread class. I had the following pseudo-line in my C++ code: pThread = new Thread(&ThreadFunction, NULL, "SomeThread"); The constructor of Thread class created a new thread with ThreadFunction as the function call. The thread itself uses bool pThread->ShouldBeRunning() to see if it had been asked to end by another process. I've noticed there's a problem with that code, as it creates a race condition. Essentially, what happens is "new Thread(...)" executes first. Only when the constructor is done, then the value of 'new' will get assigned to pThread (until then, it is == NULL). But before the constructor is done, the thread is already created so it might switch context to it and start running it. Of course, first thing the thread function does is: while (pThread->ShouldBeRunning()) {...} But the pThread = assignment might not have been done yet, so it causes a null pointer exception. I see some solutions. One is to avoid RAII here and separate pThread = new Thread() and pThread->StartThread(), where the latter function starts the thread, not the Constructor. The other solution requires passing the reference to the Thread instance (this pointer) to ThreadFunction as a parameter when creating the thread. Another way is to assign the Thread pointer inside the Constructor itself, before creating the thread within that constructor. But that leads to the following hard-to-understand code (especially after some time passes): new Thread(pThread /*passed by reference*/, ...); Which is equivalent to pThread = new Thread(...) except without the race condition. I guess the underlying issue here is that I was using a global variable/static member of a class (essentially a global too) for pThread pointer and using it within the new thread function. This is why globals are bad (I'm trying to avoid them, but this is an old project). Any suggestions/comments about my bad practice? [Edited by - shurcool on November 26, 2008 11:29:31 PM]

Share this post


Link to post
Share on other sites
Advertisement
RAII would apply if you were using it. But you're not. You give your thread function implicit knowledge of pNetworkThread, and use pointer to bypass what RAII would prevent you from:
Thread nt(&NetworkThreadFunction, NULL, "Network");
Problem solved, you cannot pass the reference to thread before it exists.

Modify your thread func to accept Thread & as parameter. Something like:

void thread_func(Thread & owner) {
while (owner.shouldBeRunning()) {
}
};

...

Thread::Thread() {
// pass *this to thread_func
};

Share this post


Link to post
Share on other sites
Hmm, well, I need to be able to control whether the thread is created or not dynamically within the application. It's easy with dynamic allocation and a pointer, but how would I do it with a regular object. Do I just wrap it within another class, and create a new instance of that class whenever I need to create the thread? That seems like a lot of extra code verbosity.

Other than that, I see the benefit in your suggestion, and thanks. :)

[Edited by - shurcool on November 26, 2008 8:27:28 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by shurcool
Hmm, well, I need to be able to control whether the thread is created or not dynamically within the application. It's easy with dynamic allocation and a pointer, but how would I do it with a regular object.


That wasn't my point, RAII applies regardless of how you allocate the object. But if you try to allocate thread on stack you'll notice you can no longer pass the instance. So there is an issue in initialization.

The example above shows how to get by the problem. I don't know which networking API you're using, but all have means to pass specific data to thread function.

Usually I'd suggest something like boost's thread, especially since it's upcoming in next C++ standard, but that one doesn't necessarily make this problem simpler.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!