Inter-thread communication in C++ #1

Posted at 2008. 10. 23. 02:08 // in S/W개발/C++ 이야기 // by 김윤수


아래 코드는 독립된 쓰레드로 동작하는 Class의 member function을 그 쓰레드 context에서 실행시키는 예제 코드. 이걸 좀더 일반적으로 작성할 순 없을까요? 예를 들어, member function 인자가 몇 개가 있더라도 호출할 수 있도록 한다던지... ITCThread에서 상속받는 클래스에서 공개 인터페이스를 쉽게 작성할 수 있도록 해준다던지...(지금은 memfun()를 public으로 하고 doMemfunc()라는 걸 private으로 선언한 다음에 memfun()를 구현해 줘야 한다.)

좋은 아이디어 있으신 독자분께서는 댓글 부탁드려용~

참고로 말씀드리면 thread, mutex, unique_lock, condition_variable, bind, mem_fn 등은 모두 boost에 있는 것들을 사용한 것입니다.

#include <iostream>

#include <string>
#include <functional>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/signal.hpp>

using namespace std;
using namespace boost;
using namespace boost::posix_time;

template <class ThreadType>
class ITCThread : public thread
{
public:
    typedef void (ThreadType::*MemFunType)();

    ITCThread(const string& name = "thr"):
        thread(bind(mem_fn(&ITCThread::run), this)),
        m_name(name),
        m_mutex(), m_cond(),
        m_req(false), m_fn(&ITCThread::noop), m_run(true) {}

    const string& getName()
    {
        return m_name;
    }

    void quit()
    {
        doIt(&ITCThread::doQuit);
    }

protected:
    void doIt(MemFunType mf)
    {
        unique_lock<mutex> lock(m_mutex);
        cout << m_name << ": calling..." << endl;
        m_fn = mem_fun(mf);
        m_req = true;
        m_cond.notify_one();
    }

private:
    void run()
    {
        cout << m_name << ": starting..." << endl;
        while (m_run)
        {
            unique_lock<mutex> lock(m_mutex);
            while (!m_req)
            {
                cout << m_name << ": waiting a call..." << endl;
                m_cond.wait(lock);
            }
            cout << m_name << ": I've got a call" << endl;
            m_fn((ThreadType*)(this));
            m_req = false;
        }
        cout << m_name << ": bye bye" << endl;
    }

    void doQuit()
    {
        cout << m_name << ": exiting..." << endl;
        m_run = 0;
    }

    void noop()
    {
        cout << m_name << ": noop() called" << endl;
    }

    string m_name;
    mutex m_mutex;
    condition_variable m_cond;
    bool m_req;
    mem_fun_t<void,ThreadType>  m_fn;
    bool m_run;
};

class HelloThread : public ITCThread<HelloThread>
{
public:
    HelloThread(const string& name = "hello") :
        ITCThread<HelloThread>(name)
        {}

    void hello()
    {
        doIt(&HelloThread::doHello);
    }

private:
    void doHello()
    {
        cout << getName() << ": Hello~ body!" << endl;
    }

};

int
main()
{
    HelloThread itc1("H1"), itc2("H2");

    for (int i = 0; i < 10; ++i)
    {
        this_thread::sleep(millisec(1000));
        itc1.hello();
        itc2.hello();
    }
    this_thread::sleep(millisec(1000));
    itc1.quit();
    itc2.quit();

    itc1.join();
    itc2.join();

    return 0;
}