Thread: C++ Threading?

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    39

    C++ Threading?

    hi...

    I'm using Microsoft Visual C++, I wanted normall C++ threading rather then WIN32 API threading...... how?


    Thanks

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    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).

  3. #3
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    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.

  4. #4
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    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

  5. #5
    Magically delicious LuckY's Avatar
    Join Date
    Oct 2001
    Posts
    856
    Check out CodePlug's thread library. You might find it very useful.

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    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:
    Code:
    //-----------------------------------------------------------------------------
    #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
    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Cross Threading Problems
    By (TNT) in forum C# Programming
    Replies: 1
    Last Post: 12-09-2006, 10:59 AM
  2. c++ threading
    By Anddos in forum C++ Programming
    Replies: 4
    Last Post: 12-28-2005, 03:29 PM
  3. Problem with threading
    By osal in forum Windows Programming
    Replies: 6
    Last Post: 07-21-2004, 12:41 PM
  4. starting to learn multi threading
    By hanhao in forum C++ Programming
    Replies: 2
    Last Post: 06-09-2004, 01:44 PM
  5. Threading
    By threads in forum C# Programming
    Replies: 0
    Last Post: 01-17-2003, 11:50 PM