我最近使用std :: atomic三重缓冲区为C++ 11创建了一个端口,用作并发同步机制.这种线程同步方法背后的想法是,对于生产者 - 消费者情况,你有一个运行速度更快的生产者,消费者,三重缓冲可以带来一些好处,因为生产者线程不会因为必须等待而"减慢"速度对于消费者.在我的例子中,我有一个物理线程,在~120fps时更新,以及一个以~60fps运行的渲染线程.显然,我希望渲染线程始终能够获得最新状态,但我也知道我将从物理线程中跳过很多帧,因为速率不同.另一方面,我希望我的物理线程保持其不变的更新速率,而不受锁定我的数据的较慢渲染线程的限制.
最初的C代码是由remis-ideas制作的,完整的解释在他的博客中.我鼓励任何有兴趣阅读它的人进一步了解原始实现.
我的实现可以在这里找到.
基本思想是使一个具有3个位置(缓冲区)的数组和一个原子标志进行比较和交换,以定义在任何给定时间哪些数组元素对应于什么状态.这样,只有一个原子变量用于模拟数组的所有3个索引和三重缓冲背后的逻辑.缓冲区的3个位置被命名为Dirty,Clean和Snap.该生产商始终写入脏指数,以及可翻转作家交换肮脏与当前清洁指数.该消费者可以要求一个新的管理单元,其交换与清洁指数当前捕捉指数以获得最新的缓冲区.该消费者总是读取对齐位置的缓冲区.
该标志由8位无符号整数组成,这些位对应于:
(未使用)(新写入)(2x脏)(2x清洁)(2x快照)
newWrite extra bit标志由写入器设置并由读取器清除.读者可以使用它来检查自上次捕捉以来是否有任何写入,如果不是,则不会再次捕捉.可以使用简单的按位运算获得标志和索引.
现在好了代码:
template <typename T>
class TripleBuffer
{
public:
TripleBuffer<T>();
TripleBuffer<T>(const T& init);
// non-copyable behavior
TripleBuffer<T>(const TripleBuffer<T>&) = delete;
TripleBuffer<T>& operator=(const TripleBuffer<T>&) = delete;
T snap() const; // get the current snap to read
void write(const T newT); // write a new value
bool newSnap(); // swap to the latest value, if any
void …Run Code Online (Sandbox Code Playgroud) Microsoft提供了InterlockedCompareExchange执行原子比较和交换操作的功能.还有一个内在的._InterlockedCompareExchange
在x86上,这些是使用lock cmpxchg指令实现的.
但是,通过阅读这三种方法的文档,他们似乎并不同意对齐要求.
英特尔的参考手册没有说明对齐(除了如果启用了对齐检查并且进行了未对齐的内存引用,则会生成异常)
我也查找了lock前缀,具体说明了这一点
锁定前缀的完整性不会受到内存领域的对齐方式.
(强调我的)
所以英特尔似乎认为对齐是无关紧要的.无论如何,这个操作都是原子的.
该_InterlockedCompareExchange固有的文档也只字未提对齐,但是InterlockedCompareExchange 功能指出,
该函数的参数必须在32位边界上对齐; 否则,该函数将在多处理器x86系统和任何非x86系统上表现不可预测.
什么给出了什么?对齐要求是否InterlockedCompareExchange只是为了确保该功能即使在cmpxchg指令不可用的486之前的CPU上也能正常工作?这看起来很可能基于上述信息,但在依赖它之前我想确定一下.:)
或者ISA需要对齐以保证原子性,我只是在英特尔的参考手册中找错了地方?
当返回值不感兴趣时,当忽略返回值时,是否存在(AtomicInteger.getAndIncrement()和实际上不相关的)AtomicInteger.incrementAndGet()方法之间的差异?
我正在考虑哪些差异会更加惯用,以及哪些会减少CPU缓存的负载同步,或其他任何事情,任何事情来帮助决定哪一个比投掷硬币更合理地使用.
对于std::atomic<T>T是基本类型的任何地方:
如果我使用std::memory_order_acq_rel的fetch_xxx操作,以及std::memory_order_acquire用于load操作和std::memory_order_release对store操作盲目(我的意思是,就像重置这些功能的默认内存排序)
std::memory_order_seq_cst(用作默认值)的任何声明操作相同?std::memory_order_seq_cst在效率方面是否与使用不同?在串行代码中,更新最大值可以简单地通过
template<typename T>
void update_maximum(T& maximum_value, T const& value) noexcept
{
if(value > maximum_value) maximum_value = value;
}
Run Code Online (Sandbox Code Playgroud)
但是,如何对atomic<T>保存最大值的变量执行此操作:
template<typename T>
void update_maximum(std::atomic<T>& maximum_value, T const& value) noexcept
{
// want a lock-free, thread-safe implementation
}
Run Code Online (Sandbox Code Playgroud)
显然,串行版本的代码不起作用,因为另一个线程可能maximum_value在加载和存储之间发生变化.可以使用compare_exchange(比较==而不是>)来实现这个吗?怎么样?
请注意,不允许显式锁定(允许的唯一锁定是执行时可能出现的锁定std::atomic<T>).
我在同一个父目录中有两个目录.调用父目录库和子目录alpha和bravo.我想用bravo替换alpha.最简单的方法是:
rm -rf alpha
mv bravo alpha
Run Code Online (Sandbox Code Playgroud)
mv命令是原子的,但rm -rf不是.在bash中有一种简单的方法可以用bravo原子替换alpha吗?如果没有,有复杂的方法吗?
附录:
如果目录在短时间内不存在,那么这不是一个不可逾越的问题.只有一个地方试图访问alpha,它会在做任何关键事情之前检查alpha是否存在.如果没有,它会给出错误消息.但如果有办法做到这一点会很好.:)也许有一些方法可以直接修改inode,或者某些东西......
我想知道我是否有这样的事情:
def functionA():
with transaction.atomic():
#save something
functionB()
def functionB():
with transaction.atomic():
#save another thing
Run Code Online (Sandbox Code Playgroud)
有人知道会发生什么吗?如果functionB失败,functionA也会回滚吗?
谢谢!
多年来我一直在使用volatile bool进行线程执行控制,它工作正常
// in my class declaration
volatile bool stop_;
-----------------
// In the thread function
while (!stop_)
{
do_things();
}
Run Code Online (Sandbox Code Playgroud)
现在,由于c ++ 11增加了对原子操作的支持,我决定尝试这样做
// in my class declaration
std::atomic<bool> stop_;
-----------------
// In the thread function
while (!stop_)
{
do_things();
}
Run Code Online (Sandbox Code Playgroud)
但它比它快几个数量级volatile bool!
我编写的简单测试用例大约需要1秒才能完成volatile bool.随着std::atomic<bool>不过,我一直在等待约10分钟,并放弃了!
我试着用memory_order_relaxed旗帜load和store同样的效果.
我的平台:Windows 7 64位MinGW gcc 4.6.x
我做错了什么?
UPD
是的,我知道volatile不会使变量线程安全.我的问题不是关于挥发性的,而是关于为什么原子是非常慢的.
UPD2 @all,感谢您的评论 - 我今晚到达机器后会尝试所有建议.
只是好奇知道哪些CPU架构支持比较和交换原子基元?
atomic ×10
c++ ×4
c++11 ×4
concurrency ×2
atomicity ×1
bash ×1
c ×1
django ×1
interlocked ×1
java ×1
linux ×1
max ×1
memory ×1
multicore ×1
nested ×1
performance ×1
transactions ×1
winapi ×1
x86 ×1