以原子方式取消排队的最简单方法
The simpliest way to dequeue atomically?
我有一组数据必须使用多线程同时处理,数据的数量应该大于线程的数量。我决定将数据放入某种队列中,以便每个空闲线程都可以弹出其部分并对其进行处理,直到队列为空。当我想将元素从中取消排队时,我可以使用简单的 STL 队列并通过互斥锁锁定它,但我想尝试一种无锁方法。同时我的项目太小,无法依赖一些提供无锁结构的第三方库,实际上我只需要原子出列。所以我决定基于一个带有指向"head"的指针的向量实现我自己的队列,并以原子方式递增这个指针:
template <typename T>
class AtomicDequeueable
{
public:
// Assumption: data vector never changes
AtomicDequeueable(const std::vector<T>& data) :
m_data(data),
m_pointer(ATOMIC_VAR_INIT(0))
{}
const T * const atomicDequeue()
{
if (std::atomic_load(&m_pointer) < m_data.size())
{
return &m_data
[
std::atomic_fetch_add(&m_pointer, std::size_t(1))
];
}
return nullptr;
}
private:
AtomicDequeueable(const AtomicDequeueable<T>&) {}
std::atomic_size_t m_pointer;
const std::vector<T>& m_data;
};
线程的函数如下所示:
void f(AtomicDequeueable<Data>& queue)
{
while (auto dataPtr = queue.atomicDequeue())
{
const Data& data = *dataPtr;
// processing data...
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
我使用无锁结构和基元的经验真的很差,所以我想知道:我的方法会正常工作吗?当然,我已经在 Ideone 上对其进行了测试,但我不知道它如何处理真实数据。
目前,您的atomicDequeue
函数存在数据竞赛:在执行第二个指令之前,2 个线程可以同时执行第一条atomic
指令。但是,这可以修复,因为您实际上只需要 1 个原子操作,如以下更改所示:
const T * const atomicDequeue()
{
auto myIndex = std::atomic_fetch_add(&m_pointer, std::size_t(1));
if(myIndex >= m_data.size())
return nullptr;
return &m_data[myIndex];
}
只要在线程操作期间不修改输入向量,这就可以工作。
你的代码非常有问题。让我在这里非常坦率地提出建议:
-
"阿加斯: 不要做已经做过的事情。" 您有大量预先存在的C++类可供您使用,这些类可以可靠地执行队列和进程间通信 (IPC)。 使用其中之一。
-
不要担心"无锁"。这就是锁的用途,它们可靠、快速且便宜。
你"使用队列"的概念是合理的,但你要做不必要的工作......并创建错误...当你可以简单地"从货架上拿东西"时。您知道标准部件将正常工作,因为其他人已经对其进行了死亡测试。
相关文章:
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 通过比较C++中的行在 txt 文件中搜索的最简单方法是什么?
- 将时间戳打印到流的最简单方法
- 在C++中创建文件夹选取器对话框的最简单方法是什么?
- boost::variant - 对变体应用算术的最简单方法
- 创建可以遍历 std::map 值的通用模板迭代器的最简单方法是什么?
- 在C++中将算术类型转换为 std::array 的最简单方法<uint8_t>
- C++-将ASCII字符数组中可能的数值转换为字符的最简单方法
- 从 txt 文件中读取数据的最简单方法
- 根据浮点符号对浮点进行舍入的最简单方法是什么
- 对于我扩展此程序来计算最高10x10矩阵的倒数的最简单方法是什么
- C++98 中获取并继续调用当前类不知道的类方法的最简单方法是什么?
- 编写要在 Python 中使用的并行 C/C++ 模块的最简单方法
- 开放式颜色多边形表面的最简单方法
- 确定代码中当前程序集是否为 32/64 位的最简单方法
- 将unique_ptr存储在堆上的最简单方法是什么
- 使用 C# 获取 OpenGL 版本的最简单方法
- 在自定义 C/C++ 程序中获取 PPP0 接口 Tx/Rx 字节的最简单方法是什么?
- 为depth_first_search定义颜色图的最简单方法