🔒 Locked
Good Thread Classes/functions
Advertisement
Original Post
I've done thread programming in Java, and I've done thread programming once or twice in C++ so I know the theory, and how I want to set it up. I'm currently working with Visual Studio 2003 .net But I'm trying to stay away from libraries except DirectX. Does anyone have suggestions for lightweight Thread classes, If I could set priority It'd be the best, but it's not required (I have an graphical thread, that's of course mission critical, and a Networking thread, and then a logical thread that's not as important as the first two) Can someone suggest a good thread class/function/system for this?
Is there such a thing as a light-weight thread class? This is one area when I write code that I am more than willing to let someone else provide a reliable and well tested design.
boost::thread without a doubt, it is hands-down the best thread class around. You can pass it a function or an object with a function call operator and it will run it. You do need boost, and boost::thread does need to be compiled and linked to your code.
* It promotes good design through the use of the synchronization primitives it offers (mutex, and condition variables)
* It's cross platform (posix, win32 and others)
* It's exception aware - you'll get minimal but sensible behavior even if your thread function throws - catch(...)
boost::thread without a doubt, it is hands-down the best thread class around. You can pass it a function or an object with a function call operator and it will run it. You do need boost, and boost::thread does need to be compiled and linked to your code.
* It promotes good design through the use of the synchronization primitives it offers (mutex, and condition variables)
* It's cross platform (posix, win32 and others)
* It's exception aware - you'll get minimal but sensible behavior even if your thread function throws - catch(...)
My voice goes to boost::thread as well :)
The project i'm working on has this (slightly modified) code to handle threads under win32:
thread.h
thread.cpp
It is not as complex as it looks like. To use it, you have to create a class which inherits from Thread and implements the threadproc() virtual.
A simple example:
The thing you must not forget is to us isStopping() in the thread proc to know wether the thread parent asked you to stop or not. The code is exception neutral - which is rather bad. If you want to implement an exeption halder, I'd suggest you to add it in threadproc_main().
HTH,
The project i'm working on has this (slightly modified) code to handle threads under win32:
thread.h
#ifndef THREAD_H#define THREAD_Hclass Thread{private: virtual DWORD threadproc() = 0;private: static DWORD WINAPI threadproc_s(LPVOID lpParameter); DWORD threadproc_main(); bool create(DWORD creation_flags); void closeHandles(); HANDLE mHandle; DWORD mThreadId; HANDLE mEventKill; HANDLE mEventBegin; HANDLE mEventStop;public: Thread(); virtual ~Thread(); bool create(); bool createSuspended(); DWORD resume(); DWORD suspend(); void setPriority(int prio = THREAD_PRIORITY_NORMAL); int getPriority(); bool destroy(); bool isStopping(); DWORD getThreadId() const { return mThreadId; } HANDLE getHandle() const { return mHandle; }};#endif // THREAD_Hthread.cpp
#include <windows.h>#include "thread.h"Thread::Thread() : mHandle(NULL), mThreadId(0), mEventBegin(NULL) , mEventKill(NULL), mEventStop(NULL){}Thread::~Thread(){ destroy();}bool Thread::create(){ return create(0);}bool Thread::createSuspended(){ return create(CREATE_SUSPENDED);}DWORD Thread::resume(){ if (mHandle) { return ::ResumeThread(mHandle); } return (DWORD)(-1);}DWORD Thread::suspend(){ if (mHandle) { return ::SuspendThread(mHandle); } return (DWORD)(-1);}bool Thread::create(DWORD creation_flags){ if (mHandle||mEventKill||mEventBegin||mEventStop) { return false; } // this event will be set when the thread will terminate mEventKill = ::CreateEvent(NULL, TRUE, FALSE, NULL); // this event will be set when the thread will really begin mEventBegin = ::CreateEvent(NULL, TRUE, FALSE, NULL); // this event will be set when we'll want stop the thread mEventStop = ::CreateEvent(NULL, TRUE, FALSE, NULL); // now we can create the thread object mHandle = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadproc_s, reinterpret_cast<LPVOID>(this), creation_flags, &mThreadId); if (mHandle && mEventBegin && mEventKill && mEventStop) return true; return false;}bool Thread::isStopping(){ if (mHandle && mEventStop) { DWORD w = WaitForSingleObject(mEventStop, 0); // the event stop had been set - hence we are in the destroy() function if (w == WAIT_OBJECT_0) { return true; } } return false;}void Thread::closeHandles(){ // destroy all the handles we created CloseHandle(mHandle); CloseHandle(mEventBegin); CloseHandle(mEventKill); CloseHandle(mEventStop); mHandle = NULL; mEventBegin = NULL; mEventKill = NULL; mEventStop = NULL;}bool Thread::destroy(){ // don't destroy a thread that has not been created... if (!mHandle || !mEventBegin || !mEventKill || !mEventStop) return true; DWORD w = WaitForSingleObject(mEventBegin, 0); if (w == WAIT_OBJECT_0) { // the thread is not suspended // tell the thread that we want to stop ::SetEvent(mEventStop); // now, wait for the thread to terminate w = ::WaitForSingleObject(mEventKill, INFINITE); // the thread is now terminated, close all handles closeHandles(); // we can leave the destroy() function return true; } else if (w == WAIT_TIMEOUT) { // the thread has not been launched yet but it exists // terminate it (violence is our friend here) ::TerminateThread(mHandle, 0); closeHandles(); return true; } // something went bad - don't kill our thread return false;}void Thread::setPriority(int prio){ if (mHandle) { SetThreadPriority(mHandle, prio); }}int Thread::getPriority(){ if (mHandle) { return GetThreadPriority(mHandle); } return THREAD_PRIORITY_ERROR_RETURN;}DWORD WINAPI Thread::threadproc_s(LPVOID lpParameter){ Thread *t = reinterpret_cast<Thread*>(lpParameter); return t->threadproc_main();}DWORD Thread::threadproc_main(){ unsigned long ul; SetEvent(mEventBegin); ul = threadproc(); SetEvent(mEventKill); return ul;}It is not as complex as it looks like. To use it, you have to create a class which inherits from Thread and implements the threadproc() virtual.
A simple example:
class MyThread : public Thread{ virtual DWORD threadproc() { while (!isStopping()) { std::cout << "a"; } return 0; }public: MyThread() { }};int main(int argc, char* argv[]){ MyThread thread; int i; if (thread.create()) { std::cin >> i; // this call is optionnal: the Thread // destructor destroys the thread if needed thread.destroy(); } return 0;}The thing you must not forget is to us isStopping() in the thread proc to know wether the thread parent asked you to stop or not. The code is exception neutral - which is rather bad. If you want to implement an exeption halder, I'd suggest you to add it in threadproc_main().
HTH,
Because when you remove the DirectX classes the threads themselves are reusable (if I want to try to port it to a different OS)
Basically my personal belief is that you should always try to use standardized tool when you can avoid doing otherwise. (only reason I'm doing DirectX, is I have a desire to learn DirectX)
Basically my personal belief is that you should always try to use standardized tool when you can avoid doing otherwise. (only reason I'm doing DirectX, is I have a desire to learn DirectX)
Quote:
Original post by kinglink
I'll look into that, thank you very much (exactly what I wanted, I try to make everything I can platform independant.
If you want to do that then you'll have to encapsulate priorities. The thread handle is not very useful (you can use it internally) therefore you can remove the accessor. The thread id is more generic, and I guess you can leave the accessor.
Anyway, I would encourage you to use boost::thread instead of our version - I'd say : "it works" but it has only be used by our team, while boost::thread had been debugged by thousand of developpers.
Regards,
I don't see documentation on how to use it (How to inherit it and such, All I see is the .hpp files which I guess tells a bit)
Is there a good document about how to set it up? (i've done a couple searches but the best I got was the www.boost.org pages)
EDIT: found the right doc but I completely don't know how to use it, the documents is just so confusing.
[Edited by - kinglink on February 18, 2005 6:54:06 PM]
Is there a good document about how to set it up? (i've done a couple searches but the best I got was the www.boost.org pages)
EDIT: found the right doc but I completely don't know how to use it, the documents is just so confusing.
[Edited by - kinglink on February 18, 2005 6:54:06 PM]
If I use the Create Thread function that's a Windows only function?
And that will create a good thread? (no flaws? no massive flaw, no crashing (assuming I don't do anything too stupid, which is asking a lot)?
(I'm still working on version one of this program, I might just do CreateThread to get the system working the first time and retool the system later for the next version.)
And that will create a good thread? (no flaws? no massive flaw, no crashing (assuming I don't do anything too stupid, which is asking a lot)?
(I'm still working on version one of this program, I might just do CreateThread to get the system working the first time and retool the system later for the next version.)
Operating system services for providing threads are in general not portable.
Spawning threads isn't the problem when it comes to threads, there are much, Much, harder problems to solve. For example, some libraries will provide support for thread pausing, suspension and termination which can be dangerous if implemented badly. Quirks of synchronization primitives between thread libraries can be a hassle - for example do you know if the mutex classes you intend to use are recursive on your platform?
To use boost download boost and boostjam from sourceforge and follow the examples on the 'Getting Started' page linked to from the boost mainpage to get it built. Add the boost install path to the path environment variable. Add boost to your compilers search paths for libraries and include. Include boost\thread.hpp in your application.
Enjoy.
Spawning threads isn't the problem when it comes to threads, there are much, Much, harder problems to solve. For example, some libraries will provide support for thread pausing, suspension and termination which can be dangerous if implemented badly. Quirks of synchronization primitives between thread libraries can be a hassle - for example do you know if the mutex classes you intend to use are recursive on your platform?
To use boost download boost and boostjam from sourceforge and follow the examples on the 'Getting Started' page linked to from the boost mainpage to get it built. Add the boost install path to the path environment variable. Add boost to your compilers search paths for libraries and include. Include boost\thread.hpp in your application.
Enjoy.
That's exactly how I thought I needed to install it but I'm going to hold off til a later version (I want to get a system working) It's a bit complex for me right now.
As for the other problems, with the exception of pausing it's all ok (and then this is only a beta where I want to make sure everything else works perfectly.) The critical section, I have a way to fix (Only five classes even can be access by all 5 threads, so a quick bool and a little Careful planning will get it working (for all threads, only one can read, and the others can write to a std::queue and that's about all the over lap is (it's a message queue for my threads), with a little "volitile" It should be perfect for a beta))
And yes I know it's not portable, I'm just using it for a couple versions til I get a better system implemented. Just seems like I might flub the Boostjam installation of Boost, I'm sure after I get something working I'll feel more up to tackling the harder problems ahead :)
As for the other problems, with the exception of pausing it's all ok (and then this is only a beta where I want to make sure everything else works perfectly.) The critical section, I have a way to fix (Only five classes even can be access by all 5 threads, so a quick bool and a little Careful planning will get it working (for all threads, only one can read, and the others can write to a std::queue and that's about all the over lap is (it's a message queue for my threads), with a little "volitile" It should be perfect for a beta))
And yes I know it's not portable, I'm just using it for a couple versions til I get a better system implemented. Just seems like I might flub the Boostjam installation of Boost, I'm sure after I get something working I'll feel more up to tackling the harder problems ahead :)
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement