我正在开发一种数据处理系统,其中信息的传入部分不断地流入,得到缓冲,然后偶尔进行处理。所以我使用双缓冲方法,其中传入的信息存储在一个缓冲区中,而另一个缓冲区被处理。像这样:
struct data_bundle_1 { /* ... */ };
struct data_bundle_2 { /* ... */ };
// ...
struct data_bundle_n { /* ... */ };
struct data_buffer {
data_bundle_1 data_1;
data_bundle_2 data_2;
// ...
data_bundle_n data_n;
std::atomic_int buffer_writer_count;
};
data_buffer double_buf[2];
std::atomic<data_buffer*> current_buf;
int current_buf_index = 0;
数据缓冲区由多个写入程序线程填充,因此data_buffer
结构中的每个数据包都将具有内部锁(最可能是基于atomic_flag
的自旋锁)以保护其免受可能的数据争用
我不太确定的是如何在切换缓冲区时避免数据争用。在使用current_buf
时,数据编写者成为读者,缓冲切换器是作者。
这是我想到的解决方案,但我不确定我的方法是否正确。
// threads #1, 2, ..., m
void data_writer_routine (/* data batch */) {
data_buffer* cur_buf = current_buf.load(std::memory_order_acquire); // (1)
cur_buf->buffer_writer_count.fetch_add(1, std::memory_order_release); // (2)
{
// in case buffer switching happened between (1) and (2)
data_buffer* new_cur_buf = curent_buf.load(std::memory_order_acquire);
if (cur_buf != new_cur_buf) {
cur_buf->buffer_writer_count.fetch_sub(1, std::memory_order_release);
(cur_buf = new_cur_buf)->buffer_writer_count.fetch_add(1, std::memory_order_release);
}
}
/* add the data batch to the buffer */
cur_buf->buffer_writer_count.fetch_sub(1, std::memory_order_release); // (3)
}
// thread #m+1
void buffer_switching_routine () {
data_buffer old_buf = current_buf.exchange(
&(double_buf[(current_buf_index=1-current_buf_index)]),
std::memory_order_release); // (4)
// waiting till all the data writers are done with the old buffer
while (old_buf->buffer_writer_count.load(std::memory_order_acquire)); // (5)
/* process the data from old_buf */
}
基本上,我想了解三件事:
std::shared_mutex
,但我真的希望避免因使用内核级同步而导致的性能损失。