Ring Buffer 구현
과제 내용
- 정수 값(데이터)을 저장한다.
- 데이터를 발생시키는 쓰레드와 데이터를 꺼내는 쓰레드에 의해 사용된다.
- 발생된 데이터는 다음 데이터 발생 전까지 저장되지 않으면 사라진다.
- 데이터 발생, 소모 주기가 정규분포를 형성하도록 구현하여 시뮬레이션 진행
- 데이터 발생기에서는 데이터를 0, 1, 2, 3, 4, 5, 6, …… 형태로 생한다. (데이터 소모기에서는 데이터가 누락되었는지 여부를 바로 파악가능)
- 여러 가지 변수(버퍼의 크기, 쓰레드 실행주기의 분포)에 따른 문제점 분석
Ringbuffer
void rtos::RingBuffer::put(int item) noexcept;`
버퍼에 정수 data를 저장한다. 빈 공간이 없는 경우 새로운 데이터를 쓰지 않고 넘어간다.(no-op)
void rtos::RingBuffer::putWithoutOverride(int item) noexcept;`
버퍼에 정수 data를 저장한다. 빈 공간이 없는 경우 빈 공간이 생길때까지 기다린다.
void rtos::RingBuffer::get();`
버퍼에서 값을 꺼낸다(FIFO). 버퍼가 비어 있는 경우 EmptyBufferReadException
예외를 던진다.
void rtos::RingBuffer::getFromNotEmptyBuffer() noexcept;`
버퍼에서 값을 꺼낸다. 버퍼가 비어 있는 경우 값이 저장될때까지 기다린다.
Simulation
Real-Time system에서 ringbuffer가 사용되는 상황을 재현
Requirements
- 생성기(producer)와 처리기(consumer)가 독립된 쓰레드에서 동일한 버퍼에 접근한다.
- 생성기와 처리기 실행주기를 설정할 수 있어야 한다.
- 생성기의 동작을 stdout에 출력한다.
설계
화살표의 방향은 데이터가 이동하는 방향
producer
- 일정 주기마다 데이터를 생성하고 버퍼에 저장한다.consumer
- 일정 주기마다 데이터를 버퍼에서 꺼낸다.observer
-msgq
에 저장된 메세지를 stdout에 출력한다.msgq
- 데이터가 생성, 처리될때의 timestamp와 처리된 내용을 저장하는 큐msgqLock
-msgq
에 할당된 mutex
변수 설정
아래의 설정값을 변경하여 측정값을 얻을 수 있다. 생성기와 처리기를 여러 개 실행할 수 있도록 구현하였다.
/**
* @brief 시뮬레이션 변수
*/
namespace SIMUL_PARAM {
const int BUFFER_SIZE = 10;
const double PROD_SIGMA = 6.0; // 데이터 발생주기 표준편차
const double CONS_SIGMA = 1.0; // 데이터 처리주기 표준편차
const int DURATION = 1000; // 시뮬레이션 진행 시간 (milliseconds)
const int DURATION_MARGIN = 20;
const int SAMPLE_SIZE = 50; // 정규분포를 이루는 주기의 개수
// testcase a
const period TA_PROD_PERIOD = 50; // 데이터 평균발생주기 (milliseconds)
const period TA_CONS_PERIOD = 40; // 데이터 평균처리주기 (milliseconds)
const int TA_PROD_NUM = 1;
const int TA_CONS_NUM = 1;
// testcase b
const period TB_PROD_PERIOD = 20; // 데이터 평균발생주기 (milliseconds)
const period TB_CONS_PERIOD = 20; // 데이터 평균처리주기 (milliseconds)
const int TB_PROD_NUM = 1;
const int TB_CONS_NUM = 1;
// testcase c
const period TC_PROD_PERIOD = 50; // 데이터 평균발생주기 (milliseconds)
const period TC_CONS_PERIOD = 60; // 데이터 평균처리주기 (milliseconds)
const int TC_PROD_NUM = 5;
const int TC_CONS_NUM = 1;
const size_t MSG_LENGTH = 80;
}; // SIMUL_PARAM
실행
-
case a) 데이터 평균 처리 속도 > 데이터 평균 발생 속도
결과
시뮬레이션 진행 시간: 1000ms
버퍼 크기: 10
표본 크기: 50
Producer의 데이터 생성주기 평균: 50ms
Consumer의 데이터 소비주기 평균: 40ms
Producer의 데이터 생성주기 표준편차: 6.00
Consumer의 데이터 소비주기 표준편차: 1.00
빈 버퍼에 접근한 비율: 25.00% (처리기는 25% 확률로 빈 버퍼에 접근하게 된다)
손실된 데이터 비율: 0.00% -
case b) 데이터 평균 처리 속도 = 데이터 평균 발생 속도
결과 시뮬레이션 진행 시간: 1000ms
버퍼 크기: 10
표본 크기: 50
Producer의 데이터 생성주기 평균: 20ms
Consumer의 데이터 소비주기 평균: 20ms
Producer의 데이터 생성주기 표준편차: 6.00
Consumer의 데이터 소비주기 표준편차: 1.00
빈 버퍼에 접근한 비율: 2.33%
손실된 데이터 비율: 0.00% -
case c) 데이터 평균 처리 속도 < 데이터 평균 발생 속도
(발생기 쓰레드 5개)
결과
시뮬레이션 진행 시간: 1000ms
버퍼 크기: 10
표본 크기: 50
Producer의 데이터 생성주기 평균: 50ms
Consumer의 데이터 소비주기 평균: 60ms
Producer의 데이터 생성주기 표준편차: 6.00
Consumer의 데이터 소비주기 표준편차: 1.00
빈 버퍼에 접근한 비율: 0.00%
손실된 데이터 비율: 21.74%
코드
reference
- Software Engineering 8th edition -Ian Sommerville
Comments