hi...
I'm using Microsoft Visual C++, I wanted normall C++ threading rather then WIN32 API threading...... how?
Thanks
This is a discussion on C++ Threading? within the C++ Programming forums, part of the General Programming Boards category; hi... I'm using Microsoft Visual C++, I wanted normall C++ threading rather then WIN32 API threading...... how? Thanks...
hi...
I'm using Microsoft Visual C++, I wanted normall C++ threading rather then WIN32 API threading...... how?
Thanks
There is no "normal" C++ threading. Or, to put it another way, the C++ standard says nothing that is related to threading, synchronisation, etc. The language doesn't support it, and there are no library functions related to threading in the C++ standard.
If you want to write multithreaded programs, you have to use either third party libraries or system specific APIs (such as the win32 API).
There is always Pthreads as well. Not standard, of course, but more portable in the sense that you can get the library for Win32 and *NIX.
A very brief search turned up this commentary on Pthreads and Win32 threads.
I've not used either directly, myself. All the interaction I've had is with higher level API-wrappers for threads.
The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.
Free the weed!! Class B to class C is not good enough!!
And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi
Check out CodePlug's thread library. You might find it very useful.
Actually, I've updated that code thanks to Stoned_Coder's suggestion of using a straight-up policy object for thread creation instead of using template specialization.
Windows specific code follows:
ggCode://----------------------------------------------------------------------------- #ifndef CP_THREAD_H #define CP_THREAD_H #include <windows.h> #if defined(_WIN32_WCE) // doesn't have assert.h # ifndef assert # define assert(exp) ((void)0) # endif #else # include <assert.h> #endif // If building with the SDK that ships with VC++ 6.0 then OLD_PLATFORM_SDK // should be defined (because it is....very old) #if defined(OLD_PLATFORM_SDK) || (defined(_WIN32_WCE) && (_WIN32_WCE < 400)) # define InterlockedExchangePointer(Target, Value) \ (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) #endif namespace CP_Thread { // Forward decl. class Thread; //----------------------------------------------------------------------------- // Compile time assertion utility template <bool assertion> struct compile_assert; template <> struct compile_assert<true> {}; // specialized on true only //----------------------------------------------------------------------------- // ThreadFunc_t - Thread function type used by the Thread class. All // thread functions return DWORD and take a Thread* // parameter. typedef DWORD (*ThreadFunc_t)(Thread*); //----------------------------------------------------------------------------- // Base class for functor object which invokes the user [member] function struct ThreadFunctor { virtual DWORD Invoke(Thread *t) = 0; };//ThreadFunctor //----------------------------------------------------------------------------- // Functor object for non-member functions struct NonMemFunctor : public ThreadFunctor { ThreadFunc_t m_tfp; NonMemFunctor(ThreadFunc_t tfp) : m_tfp(tfp) {} virtual DWORD Invoke(Thread *t) {return m_tfp(t);} };//NonMemFunctor //----------------------------------------------------------------------------- // Functor object for member functions template <typename Obj_t> struct MemFunctor : public ThreadFunctor { typedef DWORD (Obj_t::*MemberFunc_t)(Thread*); MemberFunc_t m_tfp; Obj_t *m_obj; MemFunctor(Obj_t *obj, MemberFunc_t tfp ) : m_tfp(tfp), m_obj(obj) {} virtual DWORD Invoke(Thread *t) {return (m_obj->*m_tfp)(t);} };//MemFunctor //----------------------------------------------------------------------------- // Thread creation interface class ThreadCreationIF { friend class Thread; static inline DWORD ThreadExec(Thread *t); virtual HANDLE run_thread(Thread *t, DWORD flags, LPSECURITY_ATTRIBUTES psa, DWORD stack_sz) = 0; public: ThreadCreationIF() {}; };//ThreadCreationIF //----------------------------------------------------------------------------- // Thread creation interface for Win32 API threads class Win32APIThread : public ThreadCreationIF { static DWORD WINAPI Win32ThreadProc(LPVOID pv) { return ThreadCreationIF::ThreadExec(reinterpret_cast<Thread*>(pv)); }//Win32ThreadProc virtual HANDLE run_thread(Thread *t, DWORD flags, LPSECURITY_ATTRIBUTES psa, DWORD stack_sz) { DWORD thread_id; return ::CreateThread(psa, stack_sz, &Win32ThreadProc, t, flags, &thread_id); }//run_thread };//Win32APIThread //----------------------------------------------------------------------------- // Thread creation interface for CRT API threads class CrtAPIThread : public ThreadCreationIF { static unsigned __stdcall CrtThreadProc(void *pv) { return ThreadCreationIF::ThreadExec(reinterpret_cast<Thread*>(pv)); }//CrtThreadProc virtual HANDLE run_thread(Thread *t, DWORD flags, LPSECURITY_ATTRIBUTES psa, DWORD stack_sz) { // generic decl. for _beginthreadex() so we don't have to include // process.h typedef unsigned (__stdcall *CrtCallback_t)(void*); extern unsigned long __cdecl _beginthreadex(void*, unsigned, CrtCallback_t, void*, unsigned, unsigned*); unsigned thread_id; return (HANDLE)_beginthreadex(psa, stack_sz, &CrtThreadProc, t, flags, &thread_id); }//run_thread };//CrtAPIThread //----------------------------------------------------------------------------- // Thread creation interface for MFC API threads #ifdef _MFC_VER class MfcAPIThread : public Win32APIThread { virtual HANDLE run_thread(Thread *t, DWORD flags, LPSECURITY_ATTRIBUTES psa, DWORD stack_sz) { // create the thread suspended so that we can safely duplicate the // thread handle - CWinThread will clean up its copy and we'll clean up // ours. CWinThread *t; t = AfxBeginThread((AFX_THREADPROC)&Win32ThreadProc, t, THREAD_PRIORITY_NORMAL, stack_sz, flags | CREATE_SUSPENDED, psa); HANDLE proc = GetCurrentProcess(), thrd = 0; BOOL ret = DuplicateHandle(proc, t->m_hThread, proc, &thrd, 0, FALSE, DUPLICATE_SAME_ACCESS); assert(ret); if (!(flags & CREATE_SUSPENDED)) t->ResumeThread(); return thrd; }//run_thread };//MfcAPIThread #endif //_MFC_VER //----------------------------------------------------------------------------- // Thread - Provides interface for thread objects class Thread { friend class ThreadCreationIF; //------------------------------------------------------------------------- // Member data ThreadFunctor *m_functor; HANDLE m_hthread; volatile void *m_thread_data; volatile LONG m_flags; // don't allow copies or assignment Thread(const Thread&); // no implementation Thread& operator=(const Thread&); // no implementation public: //------------------------------------------------------------------------- // enum used by SetPriority() for type safety enum Priority_t { priority_above_normal = THREAD_PRIORITY_ABOVE_NORMAL, priority_below_normal = THREAD_PRIORITY_BELOW_NORMAL, priority_highest = THREAD_PRIORITY_HIGHEST, priority_idle = THREAD_PRIORITY_IDLE, priority_lowest = THREAD_PRIORITY_LOWEST, priority_normal = THREAD_PRIORITY_NORMAL, priority_time_critical = THREAD_PRIORITY_TIME_CRITICAL, };//Priority_t //------------------------------------------------------------------------- // Constructor Thread() : m_functor(0), m_hthread(0), m_thread_data(0), m_flags(0) {} //------------------------------------------------------------------------- // Destructor - If the thread is running, it is killed (not good) virtual ~Thread() { if (m_hthread != 0) { if (IsRunning()) { assert(false); // thread shouldn't be running! Kill(); // not good }//if ::CloseHandle(m_hthread); }//if delete m_functor; }//destructor //------------------------------------------------------------------------- // Sets the thread entry point function. This is the function which is // called when the thread is started. // fun - pointer to function to execute in this thread's context void SetThreadEntry(ThreadFunc_t fun) { delete m_functor; m_functor = new NonMemFunctor(fun); }//SetThreadEntry //------------------------------------------------------------------------- // Use this version to run object member functions in the context of this // thread. // obj - pointer to struct or class instance to run the member function // thread on // fun - pointer to object member function to run in this thread's // context template <typename Obj_t> void SetThreadEntry(Obj_t *obj, DWORD (Obj_t::*fun)(Thread*)) { delete m_functor; m_functor = new MemFunctor<Obj_t>(obj, fun); }//SetThreadEntry //------------------------------------------------------------------------- // HANDLE operator for access to the thread handle operator HANDLE() {return m_hthread;} //------------------------------------------------------------------------- // Set a custom data value in the thread. Member templates are used for // convenience but only pointer-sized data types or smaller may be used. template <typename T> void SetData(T data) { // only pointer-sized data or smaller allowed compile_assert<sizeof(T) <= sizeof(void*)>(); InterlockedExchangePointer(&m_thread_data, reinterpret_cast<void*>(data)); }//SetData // For const pointer types template <typename T> void SetData(const T *data) { InterlockedExchangePointer(&m_thread_data, reinterpret_cast<void*>(const_cast<T*>(data))); }//SetData //------------------------------------------------------------------------- // Get a custom data value in the thread. Member templates are used for // convenience but only pointer-sized data types or smaller may be used. // The same type used in the SetData() call should also be used in // the GetData() call. template <typename T> void GetData(T &data) const { // only pointer-sized data or smaller allowed compile_assert<sizeof(T) <= sizeof(void*)>(); InterlockedExchangePointer(&data, m_thread_data); }//GetData //------------------------------------------------------------------------- // Set user-defined flags for this thread. Subsequent calls to GetFlags() // will return the last value set by this method. The default value is // zero. Returns the previous flags value. LONG SetFlags(LONG flags) { // casts needed by dev-c++ return InterlockedExchange((LONG*)&m_flags, flags); }//SetFlag //------------------------------------------------------------------------- // Set user-defined flags for this thread. The default value returned is // zero, otherwise it's the last value set by SetFlags(). LONG GetFlags() const { // LONG cast needed by dev-c++ return InterlockedExchange((LONG*)&m_flags, (LONG)m_flags); }//GetFlag //------------------------------------------------------------------------- // Returns false if the thread hasn't been created. Otherwise, the current // execution state of thread is returned. Note that this will return true // if the thread is suspended. bool IsRunning() const { if (m_hthread == 0) return false; return ::WaitForSingleObject(m_hthread, 0) == WAIT_TIMEOUT; }//IsRunning //------------------------------------------------------------------------- // Start the threads execution. Returns true if the thread is already // running or if the thread was started successfully. Returns false if the // thread could not be created. // tcif - thread creation object Win32APIThread(), CrtAPIThread(), // or MfcAPIThread() // flags, psa, stack_sz - see CreateThread() documentation bool Start(ThreadCreationIF &tcif, DWORD flags = 0, LPSECURITY_ATTRIBUTES psa = 0, DWORD stack_sz = 0) { assert(m_functor != 0); if (IsRunning()) return true; if (m_hthread != 0) ::CloseHandle(m_hthread); m_hthread = tcif.run_thread(this, flags, psa, stack_sz); return m_hthread != 0; }//Start //------------------------------------------------------------------------- // Calls Start(Win32APIThread(), ...) bool Start(DWORD flags = 0, LPSECURITY_ATTRIBUTES psa = 0, DWORD stack_sz = 0) { return Start(Win32APIThread(), flags, psa, stack_sz); }//Start //------------------------------------------------------------------------- // Wait for thread execution to complete. Returns true if the thread // execution has completed. Returns false if the thread was never started // or if the timeout occurred before thread execution was complete. // timeout - number of milliseconds to wait before giving up. If not // specified, an infinite timeout is used. bool Join(DWORD timeout = INFINITE) { if (m_hthread == 0) return false; return ::WaitForSingleObject(m_hthread, timeout) == WAIT_OBJECT_0; }//Join //------------------------------------------------------------------------- // Terminate the currently running thread. Returns true if the thread is // not running or if the thread was terminated successfully. // NOTE: This is a dangerous function that should only be used in the most // extreme cases. bool Kill(DWORD exitcode = 0xDEADBEAF) { if (!IsRunning()) return true; return ::TerminateThread(m_hthread, exitcode) == TRUE; }//Kill //------------------------------------------------------------------------- // Get the DWORD return value of the thread function. Returns false if the // thread was never started or the exit code could not be retrieved. // exitcode - reference parameter to receive the exit code bool GetExitCode(DWORD &exitcode) { if (m_hthread == 0) return false; return ::GetExitCodeThread(m_hthread, &exitcode) == TRUE; }//GetExitCode //------------------------------------------------------------------------- // Set the threads priority. Returns false if the thread isn't running. // Returns true if the priority of the thread is set successfully. // p - A value from the Priority_t enum. bool SetPriority(Priority_t p) { if (!IsRunning()) return false; return ::SetThreadPriority(m_hthread, p) == TRUE; }//SetPriority };//Thread //----------------------------------------------------------------------------- inline DWORD ThreadCreationIF::ThreadExec(Thread *t) { return t->m_functor->Invoke(t); }//ThreadExec //----------------------------------------------------------------------------- }// namespace CP_Thread #endif //CP_THREAD_H