我对用户空间RCU(读取 - 复制 - 更新)非常感兴趣,并试图通过tr1 :: shared_ptr模拟一个,这里是代码,而我真的是并发编程的新手,会有些专家帮我复习?
基本思想是,读者调用get_reading_copy()来获取当前受保护数据的指针(假设它是第一代或G1)。编写器调用get_updating_copy()获取G1的副本(假设它是G2),只允许一个编写器进入临界区。更新完成后,writer调用update()进行交换,并使m_data_ptr指向G2数据。正在进行的读者和作者现在持有G1的shared_ptr,读者或作者最终将取消分配G1数据。
任何新的读者都会获得指向G2的指针,而新作者会获得G2的副本(让我们说它是G3)。 G1尚未发布,因此多代数据可能共存。
template <typename T>
class rcu_protected
{
public:
typedef T type;
typedef const T const_type;
typedef std::tr1::shared_ptr<type> rcu_pointer;
typedef std::tr1::shared_ptr<const_type> rcu_const_pointer;
rcu_protected() : m_is_writing(0),
m_is_swapping(0),
m_data_ptr (new type())
{}
rcu_const_pointer get_reading_copy ()
{
spin_until_eq (m_is_swapping, 0);
return m_data_ptr;
}
rcu_pointer get_updating_copy ()
{
spin_until_eq (m_is_swapping, 0);
while (!CAS (m_is_writing, 0, 1))
{/* do sleep for back-off when exceeding maximum retry times */}
rcu_pointer new_data_ptr(new type(*m_data_ptr));
// as spin_until_eq does not have memory barrier protection,
// we need to place a read barrier to protect the loading of
// new_data_ptr not to be re-ordered before its construction
_ReadBarrier();
return new_data_ptr;
}
void update (rcu_pointer new_data_ptr)
{
while (!CAS (m_is_swapping, 0, 1))
{}
m_data_ptr.swap (new_data_ptr);
// as spin_until_eq does not have memory barrier protection,
// we need to place a write barrier to protect the assignments of
// m_is_writing/m_is_swapping be re-ordered bofore the swapping
_WriteBarrier();
m_is_writing = 0;
m_is_swapping = 0;
}
private:
volatile long m_is_writing;
volatile long m_is_swapping;
rcu_pointer m_data_ptr;
};
答案 0 :(得分:1)
乍一看,我会将spin_until_eq
次调用以及相关的自旋锁交换为互斥锁。如果在临界区内允许多个作者,那么我会使用信号量。这些并发机制实现可能依赖于操作系统,因此也应考虑性能因素;通常,他们比忙碌的等待更好。