하나의 스레드가 큰 버퍼로 메시지를 읽고 스레드를 묶어 처리하는 유스 케이스가 있습니다. 버퍼는 그 이후에 여러 스레드에 의해 공유됩니다. 읽기 전용이며 마지막 스레드가 완료되면 버퍼를 해제해야합니다. 버퍼는 lock-free slab 할당 자로부터 할당된다.boost :: intrusive_ptr을 사용한 공유 버퍼
초기 디자인에서는 버퍼에 shared_ptr을 사용했습니다. 그러나 버퍼 크기가 다를 수 있습니다. 주위를 돌아 다니는 나의 길은 이와 비슷한 것이 었습니다.
SharedBuffer allocate (size_t size)
{
auto buf = std::allocate_shared<std::array<uint8_t, 16_K>>(myallocator);
return SharedBuffer{16_K, buf}; // type erase the std::array
}
을 그리고 SharedBuffer 그것을 원하는 각 스레드의 대기열에 포함됩니다 :
struct SharedBuffer {
SharedBuffer (uint16_t len, std::shared_ptr<void> ptr)
: _length(len), _buf(std::move(ptr))
{
}
uint8_t data() { return (uint8_t *)_buf.get(); }
uint16_t length
std::shared_ptr<void> _buf; // type-erase the shared_ptr as the SharedBuffer
// need to stored in some other structs
};
이제 할당이 같이있는 shared_ptr을 할당합니다.
이제는 불필요하게 많은 일을하고 있다고 생각합니다. 다음과 같이 boost :: intrusive_ptr을 사용하면됩니다. 상황은 가변적 인 크기의 배열을 사용하기 때문에 조금 C'ish입니다. 여기에서는 단순화를 위해 new() 연산자로 슬랩 할당자를 변경했습니다. 이 구현이 괜찮은지 확인하기 위해 실행하려고했습니다.
template <typename T>
inline int atomicIncrement (T* t)
{
return __atomic_add_fetch(&t->_ref, 1, __ATOMIC_ACQUIRE);
}
template <typename T>
inline int atomicDecrement (T* t)
{
return __atomic_sub_fetch(&t->_ref, 1, __ATOMIC_RELEASE);
}
class SharedBuffer {
public:
friend int atomicIncrement<SharedBuffer>(SharedBuffer*);
friend int atomicDecrement<SharedBuffer>(SharedBuffer*);
SharedBuffer(uint16_t len) : _length(len) {}
uint8_t *data()
{
return &_data[0];
}
uint16_t length() const
{
return _length;
}
private:
int _ref{0};
const uint16_t _length;
uint8_t _data[];
};
using SharedBufferPtr = boost::intrusive_ptr<SharedBuffer>;
SharedBufferPtr allocate (size_t size)
{
// dummy implementation
void *p = ::operator new (size + sizeof(SharedBuffer));
// I am not explicitly constructing the array of uint8_t
return new (p) SharedBuffer(size);
}
void deallocate (SharedBuffer* sbuf)
{
sbuf->~SharedBuffer();
// dummy implementation
::operator delete ((void *)sbuf);
}
void intrusive_ptr_add_ref(SharedBuffer* sbuf)
{
atomicIncrement(sbuf);
}
void intrusive_ptr_release (SharedBuffer* sbuf)
{
if (atomicDecrement(sbuf) == 0) {
deallocate(sbuf);
}
}