hi...
I'm using Microsoft Visual C++, I wanted normall C++ threading rather then WIN32 API threading...... how?
Thanks
Printable View
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.
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