Message 및 Message Queue

|

메세지(Message)와 메세지큐(MessageQueue)는 이벤트(Event)들을 한 곳에서 처리하거나 멀티 쓰레드(Multi-thread) 환경에서 쓰레드간 이벤트를 전달할 때 유용하게 사용됩니다.

C++로 구현된 메세지 및 메세지큐 예제입니다. 헤더 파일로만 이루어져 있어서 include 만으로 사용가능합니다. 또한 하단부에는 메세지와 메세지큐를 활용한 메세지 핸들러(Message Handler) 코드가 있습니다. 안드로이드의 핸들러(Handler)와 유사한 구조로 되어 있습니다.


Message.h

#ifndef SNOWDEER_MESSAGE_H
#define SNOWDEER_MESSAGE_H

class Message {
 public:
  Message(int _what) : what(_what), arg1(0), arg2(0) {}
  Message(int _what, int _arg1) : what(_what), arg1(_arg1), arg2(0) {}
  Message(int _what, int _arg1, int _arg2) : what(_what), arg1(_arg1), arg2(_arg2) {}
  virtual ~Message() {}

  int what;
  int arg1;
  int arg2;

  const static unsigned int MESSAGE_CLIENT_SOCKET_THREAD_CLOSED = 100;
};

#endif //SNOWDEER_MESSAGE_H


MessageQueue.h

#ifndef SNOWDEER_MESSAGEQUEUE_H
#define SNOWDEER_MESSAGEQUEUE_H

#include <queue>
#include <mutex>
#include <condition_variable>

using namespace std;

template<class T>
class MessageQueue {
 public:
  MessageQueue(void) : mQueue(), mMutex(), mCondition() {
    mIsLoop = true;
  }

  ~MessageQueue(void) {
  }

  void clear() {
    std::lock_guard<std::mutex> lock(mMutex);
    std::queue<T> emptyQueue;
    std::swap(mQueue, emptyQueue);
  }

  void enqueue(T t) {
    std::lock_guard<std::mutex> lock(mMutex);
    mQueue.push(t);
    mCondition.notify_one();
  }

  void destory() {
    mIsLoop = false;
    mCondition.notify_one();
  }

  T dequeue(void) {
    std::unique_lock<std::mutex> lock(mMutex);
    while((mIsLoop)&&(mQueue.empty())) {
      mCondition.wait(lock);
    }
    T val = mQueue.front();
    mQueue.pop();
    return val;
  }

 private:
  std::queue<T> mQueue;
  mutable std::mutex mMutex;
  std::condition_variable mCondition;
  bool mIsLoop;
};

#endif //SNOWDEER_MESSAGEQUEUE_H


MessageHandler.h

#ifndef SNOWDEER_MESSAGE_H
#define SNOWDEER_MESSAGE_H

class Message {
 public:
  Message(int _what) : what(_what), arg1(0), arg2(0) {}
  Message(int _what, int _arg1) : what(_what), arg1(_arg1), arg2(0) {}
  Message(int _what, int _arg1, int _arg2) : what(_what), arg1(_arg1), arg2(_arg2) {}
  virtual ~Message() {}

  int what;
  int arg1;
  int arg2;

  const static unsigned int MESSAGE_CLIENT_SOCKET_THREAD_CLOSED = 100;
};

#endif //SNOWDEER_MESSAGE_H


MessageHandler.cc

#include "MessageHandler.h"

MessageHandler::MessageHandler() {
  mIsRunning = false;
}

MessageHandler::~MessageHandler() {}

void MessageHandler::start() {
  mIsRunning = true;
  mLooper = std::thread(&MessageHandler::loop, this);
}

void MessageHandler::stop() {
  mIsRunning = false;
  if(mLooper.joinable()) {
    mLooper.join();
  }
  clear();
  mMessageQueue.destory();
}

void MessageHandler::sendMessage(shared_ptr<Message> message) {
  mMessageQueue.enqueue(message);
}

void MessageHandler::clear() {
  mMessageQueue.clear();
}

void MessageHandler::loop() {
  while(mIsRunning) {
    shared_ptr<Message> message = mMessageQueue.dequeue();

    if(mIsRunning == false) {
      break;
    }

    switch(message->what) {
      case 1:
        break;

      case 2:
        break;
    }
  }
}