|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // シングルプロデューサ/シングルコンシューマのロックレス固定長キュー
9: //
10:
11: #pragma once
12:
13: #include "header.h"
14: #include <array>
15: #include <atomic>
16:
17: // reader が 1 スレッド、writer が 1 スレッドの場合にのみスレッドセーフ。
18: // 要素型 T はデストラクト不要な型(プリミティブまたはその構造体など)を
19: // 期待している。
20: template <typename T, size_t CAPACITY>
21: class SPSCQueue
22: {
23: public:
24: SPSCQueue()
25: {
26: }
27:
28: // 読み込みを開始する。
29: // 読み込み要素のポインタを返す。
30: // 読み込み要素がないときは nullptr を返す。
31: const T *BeginRead()
32: {
33: if (length == 0) {
34: return nullptr;
35: }
36: return &mem[ri];
37: }
38:
39: // 書き込みを開始する。
40: // 書き込み要素のポインタを返す。
41: // 書き込み要素がないときは nullptr を返す。
42: T *BeginWrite()
43: {
44: if (length >= CAPACITY) {
45: return nullptr;
46: }
47: return &mem[wi];
48: }
49:
50: // BeginRead で開始した読み込みをキャンセルする。
51: void CancelRead()
52: {
53: // nop
54: }
55:
56: // BeginWrite で開始した書き込みをキャンセルする。
57: void CancelWrite()
58: {
59: // nop
60: }
61:
62: // BeginRead で開始した読み込みを終了する。
63: // これ以降は BeginRead で返された要素にアクセスしてはならない。
64: // BeginRead を呼び出していないのに EndRead を呼び出してはならない。
65: void EndRead()
66: {
67: assert(length > 0);
68: ri = (ri + 1) % CAPACITY;
69: --length;
70: }
71:
72: // BeginWrite で開始した書き込みを終了する。
73: // これ以降は BeginWrite で返された要素にアクセスしてはならない。
74: // BeginWrite を呼び出していないのに EndWrite を呼び出してはならない。
75: void EndWrite()
76: {
77: assert(length < CAPACITY);
78: wi = (wi + 1) % CAPACITY;
79: ++length;
80: }
81:
82: // item をコピー投入する。
83: bool Enqueue(const T& item)
84: {
85: T *p = BeginWrite();
86: if (p == nullptr) {
87: return false;
88: }
89: *p = item;
90: EndWrite();
91: return true;
92: }
93:
94: // pitem にコピー取り出しする。
95: bool Dequeue(T *pitem)
96: {
97: const T *p = BeginRead();
98: if (p == nullptr) {
99: return false;
100: }
101: *pitem = *p;
102: EndRead();
103: return true;
104: }
105:
106: // 最大要素数を返す。
107: constexpr size_t Capacity() const { return CAPACITY; }
108:
109: // 現在の要素数を返す。
110: // 取得した直後に変化するかもしれないことに注意。
111: size_t Length() const { return length; }
112:
113: private:
114: std::atomic<size_t> length {};
115: int ri {}; // reader の index
116: int wi {}; // writer の index
117: std::array<T, CAPACITY> mem {};
118: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.