I tried to implement a SPSC with lock free tech And got a quirky Segmentation fault. the code following:
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
#define MATTER_NUM 10000
#define BUF_LEN 1024
uint64_t RingBuffer[BUF_LEN];
//uint32_t m_buffer[BUF_LEN];
std::atomic<uint64_t> head(0);
std::atomic<uint64_t> tail(0);
bool Push(const uint64_t &data) {
uint64_t tmp_tail = tail.load(std::memory_order_relaxed);
if ((tmp_tail + 1) % BUF_LEN == head.load(std::memory_order_acquire)) return false;
RingBuffer[tmp_tail + 1] = data;
tail.store((tmp_tail + 1) % BUF_LEN, std::memory_order_release);
return true;
}
bool Pop(uint64_t &data) {
static uint64_t cnt = 0;
uint64_t tmp_head = head.load(std::memory_order_relaxed);
if (tmp_head == tail.load(std::memory_order_acquire)) return false;
data = RingBuffer[tmp_head];
head.store((tmp_head + 1) % BUF_LEN, std::memory_order_release);
cnt = (tmp_head + 1) % BUF_LEN;
return true;
}
int Producer() {
for (int i = 0; i < MATTER_NUM; i++) {
while (!Push(i));
}
return 0;
}
int Consume() {
for (int i = 0; i < MATTER_NUM; i++) {
uint64_t data = -1;
while (!Pop(data));
std::cout << data << std::endl;
}
return 0;
}
int main()
{
std::thread t1(Producer), t2(Consume);
t1.join();
t2.join();
return 0;
}
There are a quirky phenomenon. When I cancel the comment "uint32_t m_buffer[BUF_LEN]" in line 10, the code magically normal run! I can't understand why this is happening.
Build in g++ (GCC) 7.5.0: g++ -std=c++11 -pthread main.cpp && ./a.out
RingBuffer[tmp_tail + 1] = data;
- needs a %BUF_LEN
. You have the occasional buffer overrun.