내 로거 용 SPSC 큐가 아래에 있습니다.어 그리 게이션이없는 SPSC 잠금 사용 가능 큐
확실히 일반용 SPSC 잠금 해제 대기열이 아닙니다.
그러나 사용 방법, 대상 아키텍처 등에 대한 많은 가정과 아래에 자세히 설명되어있는 몇 가지 허용되는 절충 사항을 고려하면 내 질문은 기본적으로 안전합니까/작동합니까? 그것은 단지 x86_64
아키텍처에 사용됩니다
- , 그래서 원자 될 것
uint16_t
에 기록합니다. - 생산자 만
tail
을 업데이트합니다. - 소비자 만
head
을 업데이트합니다. - 생산자가
head
의 이전 값을 읽는 경우 실제보다 큐에 공간이 적게있는 것처럼 보입니다. 이는 사용되는 컨텍스트에서 허용되는 제한입니다. - 소비자가 이전 값
tail
을 읽는다면, 실제보다 대기열에서 대기중인 데이터가 적어 수용 가능한 한계가있는 것처럼 보입니다.- 소비자가 즉시 최신
tail
을 얻을 수 있지만, 결국 최신tail
이 도착, 데이터가 기록됩니다 대기 : 때문에
제한은 위의 허용됩니다.
- 소비자가 즉시 최신
- 생산자가 최신
head
을 즉시받지 못해서 대기열이 실제보다 더 가득 차게 보일 것입니다. 로드 테스트에서 우리가 로그의 양과 큐의 크기, 로거가 큐를 소모하는 속도를 발견 했으므로이 제한은 효과가 없습니다. 큐에 항상 공간이 있습니다.
마지막으로를 사용하면 각 스레드가 읽는 변수가 최적화되지 않도록 방지 할 수 있습니다.
내 질문 :
- 이 논리가 맞습니까?
- 대기열 스레드가 안전합니까?
volatile
이면 충분합니까?volatile
이 필요합니까?
내 큐 :
class LogBuffer
{
public:
bool is_empty() const { return head_ == tail_; }
bool is_full() const { return uint16_t(tail_ + 1) == head_; }
LogLine& head() { return log_buffer_[head_]; }
LogLine& tail() { return log_buffer_[tail_]; }
void advance_head() { ++head_; }
void advance_hail() { ++tail_; }
private:
volatile uint16_t tail_ = 0; // write position
LogLine log_buffer_[0xffff + 1]; // relies on the uint16_t overflowing
volatile uint16_t head_ = 0; // read position
};
상식 적용 :이 방법으로 많은 lockfree 라이브러리가 SPSC 대기열을 구현하지 못하는 이유는 무엇입니까? – sehe
@ 열거 된 트레이드 오프 때문에 @sehe - 어 그리 키스를 사용하면 소비자의 읽기가 보장됩니다. 제작자의 최신 글을 볼 수 있습니다. 라이브러리 작성시 최신 쓰기가 표시되지 않을 수도 있습니다. –