【发布时间】:2019-10-29 21:21:04
【问题描述】:
我已经实现了一个 Michael 和 Scott 队列(一个并发无锁队列),但我遇到了出队操作代码重复的问题。 这个问题通常不是关于队列算法本身,而是关于如何干净地实现函数的几种变体 大多具有相同的结构。 我说的例子:
bool dequeue() {
while(true) {
// [atomically load head, tail and head->next]
auto head = m_head.load(std::memory_order_acquire);
auto head_ptr = head.get();
auto tail = m_tail.load(std::memory_order_acquire);
auto next = head_ptr->next.load(std::memory_order_acquire);
auto next_ptr = next.get();
// Are head, tail, and next consistent?
if(head == m_head.load(std::memory_order_acquire)) {
// Is queue empty or tail falling behind?
if(head_ptr == tail.get()) {
// Is queue empty?
if(!next_ptr) {
return false;
}
// tail is falling behind. Try to advance it
m_tail.compare_exchange_strong(tail, tail(next_ptr));
} else if(next_ptr){
// [ above check is result free list interaction, not part of orginal algo ]
// [Read value from next_ptr->data]
// <<<variant of operation here>>>>
}
}
}
}
我已经计划实施各种操作来代替<<<variant of operation here>>>>
包括逻辑,退出循环的if-else代码等,我想避免重复主
函数体。我应该如何进行?我至少使用 C++14 标准。
背景故事是 boost::lockfree::queue 过于受限并且
我想实现pop_if()、compare_front()、begin()这样的操作
除了<<<variant operation here>>> 部分之外,共享相同的基本出队操作代码逻辑。
【问题讨论】:
-
将通用代码移入函数中?
-
将重复的逻辑写在一个辅助函数中,你可以像 get_next() 一样调用它。然后,您的每个 API 函数都可以调用辅助函数。让辅助函数返回 next_ptr
-
这里的问题是变体代码非常依赖基代码局部变量
head,head_ptr,tail,next,next_ptr等。代码变体是取决于所有这些。我能想到的最好的办法是将所有局部变量放在一个结构中(从主容器类派生以允许访问成员变量)并将基本代码作为成员函数放在那里。然后大多数派生类将定义更多专门的操作,这些操作在locals? -
是什么决定了您要使用哪种变体?队列中的对象类型还是其他?描述两种不同的变体(最好在代码中)。
-
@Ted Lyngmo 函数变体只是容器的区成员函数。 (即容器 API)。这是一个静态的决定,我只是在考虑如何以最少的代码重复来实现不同的功能。
标签: c++ templates code-duplication