moduo 네트워크 라이브러리의 reactor 모드 (위)

moduo 네트워크 라이브러리의reactor 모드
moduo 네트워크 라이브러리의 reactor 모델은 기본적으로'non-blocking I/O + I/O multiplexing'으로 구성되고 프로그램의 기본 구조는 이벤트 순환(event loop)으로 이벤트 드라이브(event-driven)와 이벤트 리셋(event callback)의 방식으로 업무 논리를 실현한다.이 글은 진석의moduo 네트워크 라이브러리를 참조하여 간략화하고reactor 모드의 기본 구조를 추출합니다. 
1. 스레드 동기화: 베이스 동기화 원어, 상호 배척기 + 조건 변수 사용
루틴 동기화는 가능한 한 고급 병렬 프로그래밍 구축을 사용합니다.밑부분 동기화 원어를 사용하려면 가능한 한 상호 배척기와 조건 변수만 사용하십시오.호출기와 조건 변수는 다중 루틴 프로그래밍에 필요한 모든 동기화 원어를 구성하고, 이것으로 모든 다중 루틴 동기화 작업을 완성할 수 있다.
(1) 봉인 상호 배척기
봉인 호출기는 대상이 자원을 공유하는 것을 보호하고 서로 다른 대상 간에 자물쇠 분쟁이 되지 않는다.여기에서:
MutexLock 캡슐화 임계 영역.RAII 기법으로 호출기의 생성과 파괴를 봉인합니다.
MutexLockGuard 캡슐화 임계 영역의 진입과 퇴출, 즉 잠금 및 잠금 해제.그것은 창고의 대상이며, 작용역은 임계 구역과 꼭 같다.
#ifndef MUTEXLOCKGUARD_H_
#define MUTEXLOCKGUARD_H_

#include 
#include "Thread.hpp"
#include 

class MutexLock //: boost::noncopyable
{
private:
    pthread_mutex_t mutex_;
    MutexLock(const MutexLock&);
    MutexLock& operator=(const MutexLock&);

public:
    MutexLock(){ pthread_mutex_init(&mutex_,NULL); }
    ~MutexLock(){ pthread_mutex_destroy(&mutex_); }
    void lock() { pthread_mutex_lock(&mutex_); }
    void unlock() { pthread_mutex_unlock(&mutex_); }
    pthread_mutex_t* getPthreadMutex() { return &mutex_; }
};

class MutexLockGuard //: boost::noncopyable
{
private:
    MutexLock mutex_; 
    MutexLockGuard(const MutexLockGuard&);
    MutexLockGuard& operator=(const MutexLockGuard&);

public:
    explicit MutexLockGuard( MutexLock& mutex ) : mutex_(mutex)
    {
        mutex_.lock();
        std::cout<

(2) 캡슐화 조건 변수
조건 변수는 매우 밑바닥의 동기화 원어로 라인 동기화에 사용된다.직접적으로 사용하는 경우는 드물며, 보통 고위층 동기화 조치를 실현하는 데 사용된다. 예를 들어 차단 대기열 (Blocking Queue), 카운트다운 (count Down Latch) 등이다.주의 사항:
wait단에서while의 조건 표현식의 읽기와 쓰기를 보호하기 위해 mutex와 함께 사용해야 합니다.조건 표현식의 성립을 while 대신 while로 기다리는 것은 허위 깨우기 (spurious wakeup) 를 방지하는 것이다.
signal/broadcast에서 조건 표현식을 수정하려면mutex로 보호해야 합니다.
또한 조건 변수 분석 시 int pthread 호출cond_destroy(pthread_cond_t *cond);시스템이 자원을 스스로 회수하도록 해라. 그렇지 않으면 메모리 유출을 초래할 것이다.
#ifndef CONDITION_H_
#define CONDITION_H_

#include "MutexLockGuard.hpp"
#include 

class Condition
{
  public:
    explicit Condition(MutexLock& mutex) : mutex_(mutex)
    {
      pthread_cond_init(&pcond_, NULL);
    }

   ~Condition()
   {
      pthread_cond_destroy(&pcond_);
   }

   void wait()
   {
      pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
   }

   void notify()
   {
      pthread_cond_signal(&pcond_);
   }

   void notifyAll()
   {
      pthread_cond_broadcast(&pcond_);
   }

  private:
    MutexLock& mutex_;
    pthread_cond_t pcond_;
};

#endif 

2, 봉인 스레드thread
일반 다음에 새 라인을 만들어서 사용합니다
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict_attr, void*(*start_rtn)(void*), void *restrict arg);
그 중에서 첫 번째 파라미터는 라인 식별자를 가리키는 지침이고 두 번째 파라미터는 라인 속성을 설정하는 데 사용되며 세 번째 파라미터는 라인 운행 함수의 주소이고 마지막 파라미터는 운행 함수의 파라미터이다.
비즈니스 논리를 더욱 분리하기 위해 pthreaddetail::startThread () 를 위한 create 실행 함수 고정 형식입니다.실제 실행해야 하는 루틴 함수를 자원 클래스detail:::ThreadData에서 데이터 구성원이 되는 std::functiondetail::ThreadData::func.이 자원 클래스의 구체적인 구현detail::ThreadData* 데이터는 루트 함수의 매개 변수로 전송되며, 그 전에 인터페이스 Thread:::Thread (std::function) 를 통해 실제 실행해야 하는 루트 함수를 데이터 구성원 std:::function detail:::ThreadData::::func구문을 사용합니다.
pthread_create가 새 스레드를 성공적으로 만든 후 스레드 함수detail:::startThread () 에서 전송된 구체적인 자원 대상detail::::Thread Data* 호출detail::::Thread Data::::runInThread (), 최종적으로 실행해야 하는 스레드 함수detail::::::Thread Data::::::func().
#ifndef THREAD_H_
#define THREAD_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#define gettid() syscall(__NR_gettid)

pid_t gettid()
{
    return static_cast(syscall(SYS_gettid));
}
__thread pid_t t_cachedTid = 0;

pid_t CurrentThreadtid()
{
    if (t_cachedTid == 0)
    {
        t_cachedTid = gettid();
    }
    return t_cachedTid;
}

namespace detail
{

struct ThreadData
{
    typedef std::function ThreadFunc;
    ThreadFunc func_;
    std::string name_;
    pid_t tid_;

    ThreadData(ThreadFunc func, const std::string& name, pid_t tid)
      : func_(std::move(func)),
        name_(name),
        tid_(tid)
    { }

    void runInThread()
    {
        tid_ = CurrentThreadtid();
        func_();
        name_=std::string("finished");
        std::cout<(obj);
    data->runInThread();
    delete data;
    std::cout< ThreadFunc;
    Thread(ThreadFunc func) : func_(func), tidp_(0), tid_() {}
    void start()
    {
         detail::ThreadData* data = new detail::ThreadData(func_, name_, tid_);
         std::cout<

3. 사건 순환
Reactor 모드는 기본적으로 "non-blocking I/O + I/O multiplexing"으로 구성되며 "one loop per thread"를 따릅니다.프로그램의 기본 구조는 이벤트 순환(event loop)으로 I/O 멀티플렉스 select, poll, epoll 등을 통해 이루어진다.이벤트 드라이브(event-driven)와 이벤트 리셋(event callback) 방식으로 업무 논리를 실현합니다. 이 방식은 잠시 생략하고 이벤트 순환은 시스템 함수poll 지연 1s만 호출합니다.
그 중에서 EventLoop 클래스는 단일 스레드 내의 이벤트 순환 주체 구조를 실현하고 이를 바탕으로 더 나아가 EventLoopThread 클래스로 봉하여 다중 스레드 응용을 실현한다.
EventLoop 클래스: EventLoop::loop ()은 이벤트 순환 주체 함수입니다. 여기서 EventLoop::isInLoopThread ()는 "one loop per thread"를 따르기 위해 이 EventLoop 객체가 생성된 스레드에서 실행되는지 확인합니다.
EventLoopThread 클래스 중: EventLoop* EventLoopThread:::startLoop()는 인터페이스 함수이고 여기서 void EventLoopThread:::threadFunc()는 스레드 함수입니다. 이 함수는 이전 섹션의 Thread 클래스 데이터 구성원std::::function detail:::::Thread Data::func의 스레드 함수입니다.스택 객체인 EventLoop loop을 스레드 함수에 포함합니다.이벤트 순환을 진행합니다.loop();.또한 인터페이스 함수 startLoop () 의 반환 바늘은 이 스레드 함수 중의 창고 대상 loop입니다. 스레드 동기화를 해야 사용자에게 되돌려줄 수 있으며, 정해진 시간 작업과 같은 다른 다중 스레드 업무를 실현할 수 있습니다.
#ifndef EVENT_LOOP_H_
#define EVENT_LOOP_H_

#include 
#include 
#include 
#include 
#include 
#include "Thread.hpp"

class EventLoop{
public:
    EventLoop() : tid_(CurrentThreadtid()) {}
    bool isInLoopThread() const { return tid_==CurrentThreadtid(); }
    void loop();
private:
    pid_t tid_;
};

void EventLoop::loop()
{
    if( !isInLoopThread() ){
        std::cout<

 
#ifndef EVENT_LOOP_THREAD_H_
#define EVENT_LOOP_THREAD_H_

#include "EventLoop.hpp"
#include "Thread.hpp"
#include "MutexLockGuard.hpp"
#include "Condition.hpp"
#include 
#include 

class EventLoopThread
{
public:
  EventLoopThread() 
    : loop_(NULL), exiting_(false), thread_(std::bind(&EventLoopThread::ThreadFunc, this)), mutex_(), cond_(mutex_) {}
  //~EventLoopThread();
  EventLoop* startLoop();
  
private:
  void ThreadFunc();

  EventLoop* loop_; 
  bool exiting_;
  Thread thread_; 
  MutexLock mutex_;
  Condition cond_;
};

EventLoop* EventLoopThread::startLoop()
{
  //assert(!thread_.started());
  thread_.start();
  
  {
    MutexLockGuard lock(mutex_);
    while (loop_ == NULL)
    {
      std::cout<

4. 테스트
#include "EventLoopThread.hpp"
#include "EventLoop.hpp"
#include "Thread.hpp"
#include 

using namespace std;

int main()
{
  cout<loop(); //test "one thread one loop"
  sleep(3);

  return 0;
}
baddy@ubuntu:~/Documents/Reactor/s0$ g++ -std=c++11 -pthread -o testEventLoopThreadDemo MutexLockGuard.hpp Condition.hpp Thread.hpp EventLoop.hpp EventLoopThread.hpp testEventLoopThread.cpp 
baddy@ubuntu:~/Documents/Reactor/s0$ /usr/bin/valgrind ./testEventLoopThreadDemo 
==16751== Memcheck, a memory error detector
==16751== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16751== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16751== Command: ./testEventLoopThreadDemo
==16751== 
Main: pid: 16751 tid: 16751
tid 16751: create a new thread
tid 16751: MutexLockGuard lock!
tid 16751: waiting
tid 16752: Thread::func_() started!
tid 16752: MutexLockGuard lock!
tid 16752: notified
tid 16751: received notification
tid 16751: MutexLockGuard unlock!
tid 16752: MutexLockGuard unlock!
tid 16752: looping...
tid 16751: This EventLoop had been created!
tid 16752: Thread end!
==16751== 
==16751== HEAP SUMMARY:
==16751==     in use at exit: 0 bytes in 0 blocks
==16751==   total heap usage: 7 allocs, 7 frees, 74,176 bytes allocated
==16751== 
==16751== All heap blocks were freed -- no leaks are possible
==16751== 
==16751== For counts of detected and suppressed errors, rerun with: -v
==16751== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

여기서 cout 섹션 인쇄 스레드 ID는 키워드를 사용합니다pthread.주 스레드 ID는 16751입니다. 사용자가 이벤트LoopThread 대상을 만든 후에 인터페이스 함수인 이벤트Loop* 이벤트LoopThread를 호출합니다.: startLoop(), 함수 내부에 새 스레드를 만들고 ID는 16752입니다. 그리고 스레드 함수를 실행하기 시작합니다. 이 동시에 주 스레드가 실행하는 인터페이스 함수가 사용자에게 되돌아오는 값은 새 스레드와 동기화해야 합니다.
1 거짓 깨우기 방지
조건 변수 pthread 사용cond_wait () 함수는 반드시 이 조건 변수와 관련된mutex를 얻어야 합니다.또한 조건 변수는 거짓 깨우기를 방지하기 위해 반드시 하나의 순환에서 pthread 를 호출해야 한다cond_wait() 함수, EventLoop* EventLoopThread::startLoop()에서 다음을 사용했습니다.
{
    MutexLockGuard lock(mutex_);
    while (loop_ == NULL)
    {
      cond_.wait();
    }
}

 
참조 자료:
https://github.com/chenshuo/muduo

좋은 웹페이지 즐겨찾기