This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Convenient Thread Creation Submitted by

CThread - Convenient thread creation.
Implements "has a thread" relationship, rather than the typical "is a thread" relationship. Pass object and member pointers or a function pointer rather than deriving from a Thread base and overriding ThreadMain. DOES NOT demonstrate error handling, portability or multithreaded programming. Dont forget multithreaded libs. The idea is to create an object to store a member pointer. Pass this object to a generic ThreadMain. Generic ThreadMain asks the object to call the member pointer. The member pointer points to the actual ThreadMain of an arbitrary class - there is no need to derive from a particular CThread. The object needs to be a templatised to accept any type of member pointer, and virtualised so that the generic ThreadMain has a single interface for all types of the templatised object. Andrew,
a_j_harvey@hotmail.com

Currently browsing [threads.zip] (1,562 bytes) - [thread.h] - (3,713 bytes)

    ////////////////////////////////////////////////////////////////////////////////
    //
    // CThread - Convenient thread creation.
    //
    // Implements "has a thread" relationship, rather than the typical "is a thread" relationship.
    //
    // Pass object and member pointers or a function pointer rather than deriving from a Thread base
    // and overriding ThreadMain.
    //
    // DOES NOT demonstrate error handling, portability or multithreaded programming.
    //
    // Dont forget multithreaded libs.
    //

    class CThread
    {

    ////////////////////////////////////////////////////////////////////////////////
    //
    // implementation
    //

    private:

    struct SThreadMain
    {
        CThread* m_Thread;

        SThreadMain(CThread* Thread) : m_Thread(Thread)
        {
        }

        virtual
        ~SThreadMain()
        {
        }

        virtual
        void Main() = 0;
    };

    struct SFnMain : public SThreadMain
    {
        typedef void (*_F)(CThread* Thread);

        _F m_Fn;

        SFnMain(CThread* Thread, _F Fn) : SThreadMain(Thread), m_Fn(Fn)
        {
        }

        virtual
        void Main()
        {
            CThread* thread = m_Thread;
            _F fn = m_Fn;

            delete this;

            // can't access members anymore

            (*fn)(thread);
            thread->Ended();
        }
    };

    template<class _C>
    struct SClassMain : public SThreadMain
    {
        typedef void (_C::*_M)(CThread* Thread);

        _C* m_Object;
        _M m_Member;

        SClassMain(CThread* Thread, _C* Object, _M Member) : SThreadMain(Thread), m_Object(Object), m_Member(Member)
        {
        }

        virtual
        void Main()
        {
            CThread* thread = m_Thread;
            _C* object = m_Object;
            _M member = m_Member;

            delete this;

            // can't access members anymore

            (object->*member)(thread);
            thread->Ended();
        }
    };

    private:

    static
    void ThreadMain(void* Arg)
    {
        SThreadMain* main = (SThreadMain*)Arg;
        main->Main();
    }

    private:

    unsigned long m_hThread;
    bool m_End;

    ////////////////////////////////////////////////////////////////////////////////
    //
    // constructors / destructors
    //

    public:
    CThread() : m_hThread(0), m_End(false)
    {
    }

    private:
    CThread(const CThread& x);

    private:
    CThread& operator =(const CThread& x);

    public:
    ~CThread()
    {
        if(Active())
        {
            RequestEnd();
            Wait();
        }
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // thread
    //

    public:
    void BeginThread(void (*Fn)(CThread* Thread), int StackSize = 0)
    {
        SFnMain* main = new SFnMain(this, Fn);
        unsigned long h_thread = _beginthread(ThreadMain, StackSize, main);
        m_hThread = h_thread;
    }

    public:
    template<class _C>
    void BeginThread(_C* Object, void (_C::*Member)(CThread* Thread), int StackSize = 0)
    {
        SClassMain<_C>* main = new SClassMain<_C>(this, Object, Member);
        unsigned long h_thread = _beginthread(ThreadMain, StackSize, main);
        m_hThread = h_thread;
    }

    public:
    unsigned long hThread() const
    {
        return m_hThread;
    }

    ////////////////////////////////////////////////////////////////////////////////
    //
    // ipc
    //

    public:
    void Ended()
    {
        m_hThread = 0;
        m_End = false;
    }

    public:
    void RequestEnd()
    {
        m_End = true;
    }

    public:
    bool End() const
    {
        return m_End;
    }

    public:
    bool Continue() const
    {
        return !End();
    }

    public:
    bool Active() const
    {
        return m_hThread != 0;
    }

    public:
    void Wait(int Milli = INFINITE) const
    {
        if(Active())
        {
            DWORD wait = WaitForSingleObject((HANDLE)m_hThread, Milli);
        }
    }

    };

    ////////////////////////////////////////////////////////////////////////////////

Currently browsing [threads.zip] (1,562 bytes) - [main.cpp] - (1,402 bytes)

    ////////////////////////////////////////////////////////////////////////////////

    #include <conio.h>
    #include <process.h>
    #include <windows.h>

    #include <iostream>

    #include "thread.h"

    ////////////////////////////////////////////////////////////////////////////////

    void FnMain(CThread* Thread)
    {
        int i = 0;
        while(Thread->Continue())
        {
            std::cout << "FnMain:     " << i++ << std:: endl;
            Sleep(500);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////

    class CClassMain
    {

    public:
    void ClassMain1(CThread* Thread)
    {
        int i = 0;
        while(Thread->Continue())
        {
            std::cout << "ClassMain1: " << i++ << std:: endl;
            Sleep(510);
        }
    }

    public:
    void ClassMain2(CThread* Thread)
    {
        int i = 0;
        while(Thread->Continue())
        {
            std::cout << "ClassMain2: " << i++ << std:: endl;
            Sleep(520);
        }
    }

    };

    ////////////////////////////////////////////////////////////////////////////////

    void main()
    {
        CThread t1;
        CThread t2;
        CThread t3;
        CClassMain c;

        t1.BeginThread(FnMain);
        t2.BeginThread(&c, &CClassMain::ClassMain1);
        t3.BeginThread(&c, &CClassMain::ClassMain2);

        std::cin.get(); // wait for a keypress then quit
    }

    ////////////////////////////////////////////////////////////////////////////////

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.