vir*_*ino 3 c linux bit-manipulation x86-64 atomic
我正在尝试在 Linux 下用 C 语言编写我的第一个多线程程序。我已经有一个程序在大缓冲区中设置和重置位,现在我只想让它更快 - 尽可能快,而不用在汇编程序中编写所有内容。
对于单线程程序,我为位操作定义了自己的宏(它们看起来又大又丑,但它们有效):
#define CELL_SIZE (64)
#define getBit(bitIdx, arr) ( arr[ (bitIdx) / CELL_SIZE ] & ( (1uL << (CELL_SIZE - 1)) >> (bitIdx) % CELL_SIZE))
#define resetBit(bitIdx, arr) ( arr[ (bitIdx) / CELL_SIZE ] &= ~( (1uL << (CELL_SIZE - 1)) >> (bitIdx) % CELL_SIZE))
Run Code Online (Sandbox Code Playgroud)
显然,这些操作绝非原子操作。
我做了一些研究,找到了几个答案。一些答案是关于如何在汇编程序中编写我自己的函数(我想避免)。
其他网站(这个或这个)似乎准确地谈论了我所需要的 - 除了我不知道如何使用这些接口/宏。
我尝试了以下包含,但它们不起作用。
#include <linux/bitmap.h>
#include <asm/bitops.h>
Run Code Online (Sandbox Code Playgroud)
所以,基本上,我问如何使用已经实施的内容来完成我的工作?我应该包含哪些标头?
我不介意接口是否不在内核中,只要工作完成即可。
注意:每个线程都会一次(重新)设置一位——我不打算做任何 VOODOO 复杂的事情。
一个附带问题是:哪一个更快(总体而言,用伪代码编写):
reset_bit();
Run Code Online (Sandbox Code Playgroud)
或者
if ( bit_is_set() )
reset_bit();
Run Code Online (Sandbox Code Playgroud)
通常情况下,reset_bit() 操作是不必要的,因为该位已经复位。关于设置设置位的同样问题。
为了直接回答这个问题,最直接、最容易获得的解决方案是 C11 <stdatomic.h>,任何用于多处理器系统的现代 C 编译器都应该提供它。
可用操作包括原子 OR/AND,可用于设置和清除位。所以你可能会这样做
#include <stdatomic.h>
#include <stdint.h>
#include <stddef.h>
typedef uint64_t cell_t;
#define CELL_SIZE (64)
static inline _Atomic cell_t *get_cell(size_t bitIdx, _Atomic cell_t *arr) {
return arr + (bitIdx / CELL_SIZE);
}
static inline cell_t get_mask(size_t bitIdx) {
return (1uL << (CELL_SIZE - 1)) >> (bitIdx) % CELL_SIZE;
}
static inline cell_t getBit(size_t bitIdx, _Atomic cell_t *arr) {
return atomic_load(get_cell(bitIdx, arr)) & get_mask(bitIdx);
}
static inline void resetBit(size_t bitIdx, _Atomic cell_t *arr) {
atomic_fetch_and(get_cell(bitIdx, arr), ~get_mask(bitIdx));
}
static inline void setBit(size_t bitIdx, _Atomic cell_t *arr) {
atomic_fetch_or(get_cell(bitIdx, arr), get_mask(bitIdx));
}
Run Code Online (Sandbox Code Playgroud)
我冒昧地用内联函数替换了您的宏,这在几乎所有情况下都是更好的选择。
*_explicit在某些平台上,通过使用带有 的版本,您也许可以在一定程度上加快速度memory_order_relaxed,但这在很大程度上取决于函数的使用方式,并且内存排序的介绍超出了本文的范围。
对性能的影响更加困难。通常,原子读-修改-写操作比非原子慢很多。如果 CPU 之间存在缓存线争用,速度会进一步减慢。除非您能够很好地控制这些方面,否则您计划使用更多核心来完成任务可能会使其速度变慢。
至于你最后一个关于是否先测试位的问题,很难说。加载通常比读取-修改-写入更快。然而,进行测试和条件分支的成本,尤其是错误预测该分支的可能性,可能会抵消节省的成本。
| 归档时间: |
|
| 查看次数: |
785 次 |
| 最近记录: |