I think what you need is the Win32 function TerminateThread. I don't have the C library function equivalent.
Mark
Cornutopia Games
http://www.cornutopia.net
This must be the most basic question imaginable, yet I cannot find the answer anywhere.
Okay, I'm starting a thread using handle=_beginthread (win32). When my program ends, I want this thread to shut down too, but I see no way to do this, anywhere.
Does anyone know the top secret way to just make that thread quit? Is there no _terminatethread(handle)? (Note: I know of the existence of _endthread, but it appears you can only call that from WITHIN the thread. I want to terminate it from outside).
Thanks in advance!
I think what you need is the Win32 function TerminateThread. I don't have the C library function equivalent.
Mark
Cornutopia Games
http://www.cornutopia.net
The way I've always handled it, is to terminate from the inside. That way you get to clean up everything properly.
Use something to allow synchronisation between the thread and the main process, a signal or event of some sort, and when you want to close the thread, send the signal. The loop inside the thread gets the signal to close, cleans itself up, and then closes neatly.
cheers
John
From MSDN on TerminateThread
This function is used to cause a thread to exit. When this occurs, the target thread has no chance to execute user-mode code.
DLLs attached to the thread are notified that the thread is terminating.
It also terminates the thread process only if the thread in question is the main or primary thread.
TerminateThread is a dangerous function. Use it only in the most extreme cases.
Call this function only if you know exactly what the target thread is doing and you control all code the target thread could be running at the time of the termination.
The following list shows examples of problems that can result by calling TerminateThread:
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
A thread cannot protect itself against TerminateThread other than by controlling access to its handles. The thread handle returned by the CreateThread and CreateProcess functions has THREAD_TERMINATE access, so any caller holding one of these handles can terminate your thread.
If the target thread is the last thread of a process when this function is called, the thread's process is also terminated.
The state of the thread object becomes signaled, releasing other threads waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.
Terminating a thread does not necessarily remove the thread object from the system. A thread object is deleted when the last thread handle is closed.
A thread cannot be terminated while making a system API call. When the API call is complete and the thread returns to the executing process's address space, it is terminated. If the thread never returns from a system API call, it is not terminated.
cheers
John
That *is* in fact the recommended way of terminating a thread. The signal could be something as simple as a true/false flag that both the sub-thread and the main thread can access. The sub-thread should then simply run in an infinite loop, optionally sleeping at intervals to avoid hogging the processor. At every iteration, the flag is checked and if it is set, the thread breaks out of the loop and reaches it's natural end.Originally Posted by Bluecat
Often, you may need to explicitly wait for a thread to terminate before executing further code and hence simply setting a 2-way flag may not be enough because you would need some sort of signal from the sub-thread to notify the main thread that is finished.
One way to accomplish this is to have a 3-state flag, i.e., with values for RUNNING, STOP_REQUESTED, and STOP. The thread initialises with the flag set to RUNNING. To stop the thread, the main thread sets the flag to STOP_REQUESTED and waits until it changes to STOP. In the meantime, the sub-thread must check the flag at every iteration and if the value is STOP_REQUESTED, the thread breaks out of the loop and sets the flat to STOP just before reaching it's natural end.
If you're into OO, it makes sense to encapsulate this functionality in a Thread or Process class (I know... Java has one - of sorts) and implement methods to stop (synchronously or asynchronously as above) by simply calling a thread method. The class would be designed with over-writable methods OnInit(), OnRun() and OnShutdown() to contain the "meat" of the thread while the thread class handles the flag management transparently.
Anyway, in most cases the above could be overkill but it does come handy if you're dealing with multiple threads.
Nemesis
Dudes... I know how to poll to get a thread to quit. But I'm using threads exclusively for code that doesn't loop in any way. To terminate it the "right way" (you college boys gotta get off this 'right way' stuff), I'd have to put an if statement between every statement of my threaded function.
TerminateThread looks like what I need, thankyaverymuch. Now, to find out what the consequence of using it are.![]()
One of the projects we did at my last job made use of lots of threads. Chances are TerminateThread really, really isn't what you want. It will cause you to leak memory, not call destructors in the thread, etc.
I recommend looking into terminating the threads from the inside using a "shouldQuitNow" flag for each thread which causes the thread function to return.
Just make a reference to Nazis...
Oh sorry, wrong "thread"Seriously, couldn't resist and many pardons for the off-topic post.
Bill
If it doesn't loop in any way, then what is the problem? Just wait until it's done???Originally Posted by Raptisoft
TerminateThread is an absolute last resort. Something you do in your highest level exception handler code as your code is crashing, so that it crashes a little bit better. Using it as part of the normal operation of your game would be a bad thing to do.Originally Posted by Raptisoft
When it comes to multithreaded programming, you'd be wise to consider "the right way" to do things up front. This isn't like design patterns or pure OO or other pointy-headed academic stuff. If you do things "the wrong way" when it comes to threading, your program is going to be a buggy mess of random problems that are extremely difficult to track down.
Code that does not loop in any way is code that should not take too long to finish unless it is a lot of waiting code. In my experience with windows services and lots of threads (really a lot) I never never needed the TerminateThread function. You should consider NOT using it IMO.Originally Posted by Raptisoft
Alas, this is a free world, so you can do whatever you like, but I personally would not like to have your code running on my machine if I new that you use TerminateThread!![]()
Well, I've played enough buggy games, and used enough buggy software to be a bit of a believer in doing things the right way. Besides, while the right way may need a little more effort, it's generally not that hard.Originally Posted by Raptisoft
See my previous post on TerminateThread, but it is a last resort and has some dangers. It looks like the biggest problem is screwing up a DLLs state which could make it necessary to reboot the system.
cheers
John
I guess I should have read (into) your post more thoroughly first time round, sorry! Since the viable alternatives have already been posted by someone else there's no point in me repeating. But yes, IMHO you should really avoid terminating threads the brute way - then again, it's your code...Originally Posted by Raptisoft
Since "text book" recommendations are not your kind of thing I'll share some practical experience: I've worked with threads, mostly building client-server apps in Java and in .NET at my day job. It didn't take long for me to realise that it's not a good idea to terminate threads explicitly, even if they are one-off background tasks. (I had Java instances / Windows .NET processes still running after the application quit, and had to kill them off manually) In general it is best to leave such one-off threads running till the end and poll from the main thread until they terminate naturally. A typical example is loading graphics / sound resources in the background, or streaming audio, as these kind of processes require one-off threads. Care needs to be taken when the main application is quiting since it must have a way of getting any one-off threads that may be running to terminate before quitting. Assuming you'd rather not kill them off mercilessly with TerminateThread(), it is generally safer to poll for all such threads to finish first before terminating the application.
By the way.. I'll take your "college boy" remark as a reference to my youthful looks since I'm hitting 30 in the next few weeks...
There I go again.. I try to lurk, but I can't help posting the occasional ramble.. often without reading the posts thoroughly!
Nemesis
Okay Gringos, so we're clear:
I'm loading my graphics/sounds/etc in a thread. I do all kinds of stuff in this thread, stuff like:
void LoadingThread()
{
mGraphic.Load("Graphic.bmp");
mGraphic.Flip();
mGraphic.Polarize();
mGraphic.Solarize();
mGraphic2.Load("CollegeBoy.jpg");
mGraphic2.Shrink();
mGraphic2.Squash();
mSound.Load("agony.wav");
mSound.Slow(.50);
...and so on
}
So you see, the option to put a little "if mGame==done" between each statement... well, just being told that option over and over again makes me want to DOS each and every one of you.
The only time this thread would get terminated would be if someone closes the game window during load. I'd rather not have a process "loading" graphics for the next 20 seconds after they think it's closed down, but I will if I must.
If that were my code, I would seriously consider rewriting it to load the graphics and sounds in a loop. Something like this:
That would not only make it easier to terminate the thread the right way, but would also make the code more managable in general.Code:for (int i = 0; i < num_graphics; ++i) { mGraphics[i].Load(graphic_files[i]); if (graphics_properties[i] & REQUIRES_SQUASHING) { mGraphics[i].Squash(); } // Other special processing here. }
Rainer Deyke - Eldwood
If your (Raptisoft's) code is structured the way you show above, where are you locking access to any non-const objects before modifying them to ensure the main thread doesn't try reading from an object while the loader thread is writing to it? You are doing that, right?
If not, your code will likely run fine on your machine (assuming you have a single processor box), and then fail spectacularly in some way that is very non-obvious the first time some user tries to run it on a true multiprocessor machine.
You can do it any way you want.. as others have said, its your code. But doing half-assed threading causes a lot more problems than it solves.
Good luck.
It's a loading thread. Nothing gets accessed during load unless it's already loaded (as indicated by a variable set as the last line of the loading thread). Holy smokes, guys, this isn't CIS101.
As for that other, inferior way of loading above... that doesn't permit you to do special load-time effects on things you're loading. This way I get complete flexibility. Heck, half my images aren't even loaded, they're generated during the load.
You can make use of semaphores or event objects to set up a system where you can join on a thread, i.e. pause execution of one thread (usually the main thread) until another thread has finished. This will require that you encapsulate your thread data in a class/struct if you haven't already, but it is not too dificult to set up. So then you can do something like this:Originally Posted by Raptisoft
The stop function can do nothing in the case where the thread does not loop (such as with your loading thread example), and in cases where you have a loop it can set a running flag to false that the loop can respond to In both cases, the join function blocks on the semaphore/event object/whatever until the thread has exited. Once all of the threads have completed, you can safely start shutting down the various subsystems without fear of disrupting anything.Code:Thread *thread = new Thread(); thread.start(); // then later, the user has decided to quit the game, first make sure active threads are finished for (each thread in active thread list) Thread *thread = activeThreadList.getThread(); thread.stop(); thread.join(); delete thread;
On Win32 you can use WaitForSingleObject() to wait until the thread completes (i.e. what "join" would do). But personally, I wouldn't use a thread here at all. Avoid them at all costs unless they are absolutely necessary.![]()
I believe it was Winston Churchill who famously said, "When I ask you for a specific Win32 function to perform an action, why do you reply to me with the philosophy of programming in general?"
I think those words make a heck of a lot of sense, even today.
I don't know what to say, just that we're trying to help! The problem is that there is no Win32 function to cleanly stop a thread.
In the words of Metallica, who suck incidentally but when I were a lad my brother used to listen to them 24/7 and the lyrics have become drummed into my head, "Sad but True".
If you knew the "right" answer all along, why didn't you just Google the function or look it up on MSDN?Originally Posted by Raptisoft
Since you've posted this on a forum, chances are you will get opinions from people who are trying to be helpful, whether you deem them inferior or otherwise. The least you can do is accept them politely and make up your own mind whether they apply to you or not. After all, your original post was very terse, so the chances are you will get stock answers becase other people cannot read your mind.
I have great admiration for your talent.. your games speak for themselves, but I've very disappointed with your attitude.
Nemesis
Holy cow!
I didn't know the right answer! And I did google for it! But it took someone in this thread to tell me "TerminateThread" works (I was looking for an ansi C version, which doesn't evidently exist, but Win32 is fine).
But geez, I mean, if someone writes "I have a memory array and I want to copy it to the screen, how do I do that?" why is it a universal response of programmers to say "why do you want to do that? Use DirectX and draw textures."
Incidentally, allow me to apologize in advance for any offense I've given on this thread (or will give in the future). And allow me to explain:
It's universal. If you ask a programmer how to do something, he will question your motives in doing it, and tell you a way to accomplish what you want that only requires the small task of rewriting everything you have from scratch.
I've encountered this on countless forums, across ten years. I don't usually make a stink about it. I make a stink here because I have more regard for these forums than any I've ever been on before. This is sort of like when your best friend takes you aside and says "No, friend... crossing Robotron and Bejewelled will not work. Please. Trust me, drop it, it sucks." He's doing it out of love.
I say this because the tech end of this forum, at least, should be fairly specific, and should assume someone knows what they're doing except in the context of the specific question they asked (for instance, I know all these 'proper' solutions. But I seek flexibility in my current project-- if TerminateThread didn't exist, or hadn't worked, I would have just let the thread run. Luckily, it works fine).
Most people here have finished at least one game. You do NOT finish a game without being almost superhumanly 1) adaptable 2) careful 3) open minded about your programming and 4) persistent. Often a newbie will say something like, "I want to plot textures" or "I set up a thread for each object in my game, is that right?" Those questions can be answered philosophically. But when someone asks specifically "what's the function to [x]," then I don't think it's appropriate to get into a "here's how I would do it, even though I never peeped into the 50,000 lines of code you already have in place."
It's very frustrating to seek a specific answer, but be deluged with recommendations that you stop seeking the answer and do it all another way. Over and over again.
I am a bit shocked at the huge negative response Raptisoft has recieved just for asking for a function!
Mark
Cornutopia Games
http://www.cornutopia.net
Actually it does. Look at the code again.Originally Posted by Raptisoft
Rainer Deyke - Eldwood
Originally Posted by Raptisoft
Really it is a different situation. Microsoft's own employees say "Nobody should ever call TerminateThread. Ever."
Another universal thing about programmers is if you give them advice based on your own past experience, they'll often ignore it or take it as a personal attack and stubbornly continue down the path they are on.It's universal. If you ask a programmer how to do something, he will question your motives in doing it, and tell you a way to accomplish what you want that only requires the small task of rewriting everything you have from scratch.
Using TerminateThread isn't a subjective implementation detail, like whether to use OO or prodcedural programming, but rather a practical matter, like "don't ever assume a surface's pitch is the same as its width". In that situation (just as with using TerminateThread) a naive programmer might test things on their own system and see that things work just fine -- that's great, but it still doesn't mean things are going to work just fine when the code is being used by lots of people on lots of configurations.
Who said anything about personal attacks? I am attacking the tendency of programmers to answer a yes/no question with the history of programming, starting with the ENIAC and ending with why you should save four cycles because you only have 1,000,000,000 to spare each second.Another universal thing about programmers is if you give them advice based on your own past experience, they'll often ignore it or take it as a personal attack and stubbornly continue down the path they are on.
TerminateThread works beautifully. Beautifully.
I'll let the MS dudes blog say it:Originally Posted by Raptisoft
- Realistically, Win32 shouldn’t contain a TerminateThread service.* To a first approximation, anyone who has ever used this service has injected a giant bug into his application.
- if you ever call TerminateThread you may as well kill the process.* It’s almost guaranteed to be in a corrupt state.
- For example, you may have terminated the thread while it holds the lock for the OS heap.* Any thread attempting to allocate or release memory from that same heap will now block forever.
- Nobody should ever call TerminateThread.* Ever.
cheers
John
James,
I guess I overreacted a little there. I see your point and I understand your frustration. But the fact is that even the most seasoned indies with decades of tech and business experience may not know everything, so it's unlikely that a poster will assume that you know all that is to be known except for the one question that you're asking. My first impression when I saw the post was "he must be new to using threads if he's looking into terminating them forcefully" despite being accompanied by the thought "that's weird.. this guy's a pro". Still I assumed the former because I thought that sharing some knowledge could't possibly hurt.
And really, I mean what's so bad about someone hinting at alternative ways of doing things other than your own way? A lot of the time, yes, you'll find that a suggestion is useles in your particular case, but ironically, it might also inspire you to a solution no-one else thought or suggested. It's why brain-storming works, even with sh***y ideas.
Anyway.. just to get back on track a little. In your particular case, most of the side-effects of TerminateThread should not be an issue because your application is ending anyway (stacks, heap, thread's kernel state will be dumped). But there's still a risk of leaving DLL's in an unusable state after the application ends, possibly affecting other applications. This is a potential source of intermittent problems that could keep your (or those of other application's) support people busy.
But perhaps the best way is to just give it a go. If it works with no problem at all (once tested on many configurations), it will be a reminder to us all that conventional wisdom doesn't always apply![]()
Nemesis