moduo 네트워크 라이브러리의 reactor 모드 (위)
9538 단어 linux 네트워크 프로그래밍
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
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
socket 리셋 서버server.c client.c...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.