- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有一个无锁堆栈here基于来自 Crossbeam 的基于纪元的回收。
我添加了一些注释来帮助我理解这个实现。
#[derive(Debug)]
pub struct TreiberStack<T> {
head: Atomic<Node<T>>,
}
#[derive(Debug)]
struct Node<T> {
data: ManuallyDrop<T>,
next: Atomic<Node<T>>,
}
impl<T> TreiberStack<T> {
pub fn new() -> TreiberStack<T> {
TreiberStack {
head: Atomic::null(),
}
}
pub fn push(&self, t: T) {
let mut n = Owned::new(Node {
data: ManuallyDrop::new(t),
next: Atomic::null(),
});
let guard = epoch::pin();
loop {
let head = self.head.load(Relaxed, &guard); // (1) ’Relaxed’ only provides atomicity
n.next.store(head, Relaxed); // (2) ‘Relaxed’ only provides atomicity
// (2) uses ‘head’ from (1). so (2) and (1)’s partial order won’t be rotated by CPU and compiler
// it seems that compare_and_set behaves just like compare_and_swap.
// It guarantees that all
// memory operations before the RELEASE operation will appear to happen
// before the RELEASE operation with respect to the other components of the system.
// So (1) and (2) always execute before (3)
match self.head.compare_and_set(head, n, Release, &guard) { // (3)
Ok(_) => break,
Err(e) => n = e.new,
}
}
}
pub fn pop(&self) -> Option<T> {
let guard = epoch::pin();
loop {
// It guarantees that all memory
// operations after the ACQUIRE operation will appear to happen after the
// ACQUIRE operation with respect to the other components of the system.
let head = self.head.load(Acquire, &guard); // (4)
match unsafe { head.as_ref() } {
Some(h) => {
let next = h.next.load(Relaxed, &guard); // (5) ’Relaxed’ only provides atomicity
if self
.head
.compare_and_set(head, next, Release, &guard)
.is_ok() // (6)
// This RELEASE matches the ACQUIRE in (4). Code between them won’t be reordered by CPU and compiler
{
unsafe {
guard.defer_destroy(head);
return Some(ManuallyDrop::into_inner(ptr::read(&(*h).data)));
}
}
}
None => return None,
}
}
}
// Returns `true` if the stack is empty.
pub fn is_empty(&self) -> bool {
let guard = epoch::pin();
self.head.load(Acquire, &guard).is_null() // (7)
}
}
impl<T> Drop for TreiberStack<T> {
fn drop(&mut self) {
while self.pop().is_some() {}
}
}
我的问题是:我可以将 (7) 的 Acquire
替换为“Relaxed”吗?似乎 (7) 处的 Atomicity 足以使其工作。 Acquire
通常与 Release
配对以提供 Visibility
:
after an ACQUIRE on a given variable, all memory accesses preceding any prior RELEASE on that same variable are guaranteed to be visible. In other words, within a given variable's critical section, all accesses of all previous critical sections for that variable are guaranteed to have completed.
Visibility
在此代码中扮演什么角色?看起来代码的顺序和原子性是我需要使这段代码工作的唯一保证。如果没有 Visibility
,其他线程最终将看到 store
的结果。所以代码仍然可以正常工作。
我主要从 Linux Kernel 的文档中学习无锁 here
最佳答案
My question is: Can I replace (7)'s Acquire with 'Relaxed'? It seems that Atomicity at (7) is sufficient enough to make it work.
假设我们使用 Relaxed
而不是建议的 Acquire
。 (3) 处的 Release
不保证 is_empty()
会看到调用 push()
的线程的内存访问。对于像
if !my_stack.is_empty() {
let elem = my_stack.pop().unwrap();
// Do things with elem...
} else {
// Do something expensive...
}
[...] the other thread will see the outcome of store eventually.
你是对的。但是,我想尽量减少执行昂贵操作的时间。在上面的代码片段中,我希望 is_empty()
和 pop()
始终指示我的堆栈处于相同状态。如果这些方法使用不同的原子顺序,我们将失去这种保证,并且我们可能最终会因为 is_empty()
尚未同步而完成更昂贵的工作。
此外,Treiber 的无锁堆栈可用于多消费者、多生产者上下文。假设一个线程正在调用 push()
,第二个线程正在调用 pop()
,第三个线程通过 is_empty()
观察堆栈的状态>。如果没有 Acquire
内存顺序,第三个线程无法保证观察到推送或弹出线程观察到的相同状态。
关于rust - 无锁堆栈,将 is_empty() 中的 Acquire 替换为 Relaxed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57746675/
condition.acquire(threading.Condition()) 是否类似于lock.acquire(threading.Lock)。两者都可以访问锁吗?我可以使用condition.
我正在尝试执行一个非常基本的示例,演示 accumulate() 的使用Drools 的函数,但出现 java.lang.NullPointerException 异常。 代码如下: Metric.j
我是java初学者,我正在尝试信号量。我尝试编写一个具有编写器和读取器的代码,我只尝试使用 acquire() 和 release(): 1) If a writer is writing, then
我的一个程序中有一个奇怪的问题,一个线程获取一个条件,而另一个线程告诉我没有获取该条件。 为了知道线程是否获得了条件,我做了一些调试信息,看起来是的,他做到了。但是另一个线程告诉我条件没有获得。 这是
我的类(class)有一个互斥锁,定义如下: ACE_Mutex m_specsMutex; 当我使用不带参数的 acquire() 方法时,一切正常。但是当我将它与时间值一起使用时(如下所示),它会
我使用 QSharedMemory 和 QSystemSemaphore 来组织多个进程之间的事件交换。 QSharedMemory 存储接收者的数量和事件数据。接收者在 QSystemSemapho
我正在为我的 REST 服务编写一个 API 库。在某些时候,访问 token 将需要更新。我正在尝试实现一种线程安全的方法来执行此操作,以便仅发送一个更新请求,即使多个线程可能想要同时更新它。 这是
我正在我的node.js 项目中使用MySQL 数据库。我用 Knex 创建了一个数据库查询,结果没问题。但是当我再次尝试查询时,出现此错误: Error: Unable to acquire a c
以下锁定机制用于防止 cron 作业并发运行: #!/bin/bash echo "Before critical section" ( flock -e 200 echo "In c
在 Python 3.4.3 上,我无法理解 threading.Lock.acquire() 如何阻塞,直到锁定状态设置为解锁。 threading.Lock 似乎是上面链接的 _dummy_thr
我有一段代码 locked = lock.acquire(False) if locked: break 根据 python 文档: lock.aquire(False):-
-Thread 1- y.store (20, memory_order_release); x.store (10, memory_order_release); -T
我最近在运行测试时遇到了这个错误。我在本地 MongoDB 服务器 (4.0.5) 上试过了,我也在 Mongo Atlas 上试过了,但遇到了同样的问题。 我尝试增加锁定超时,但没有效果。 我不确定
在Windows平台上,TCriticalSection是通过调用Windows API EnterCriticalSection/LeaveCriticalSection来实现的。 Microsof
我为我的数据库使用 mssql ( https://www.npmjs.com/package/mssql ) 模块。通常我使用导致 pg ( https://www.npmjs.com/packag
我在 Python 中有这个示例,它演示了条件变量的使用。 import logging import threading import time logging.basicConfig(level=
我希望我的应用保持 CPU 运行但关闭屏幕以最大限度地减少电力浪费。 关于此主题的先前帖子建议采用以下方法: mPm = (PowerManager) getSystemService(Con
是否可以在 C#.NET 应用程序中请求 Windows 7 PC 上的管理权限? 我希望能够通过 Click Once 部署应用程序,并让用户使用它来执行管理任务(在本例中,它正在为主应用程序编写注
我正在更新 Delphi (Delphi 2009) 代码,它专门使用 TCriticalSection.Acquire/Release 对,而不是 Enter/Release 或 Leave 对。我
我试图理解使用条件变量时丢失唤醒的问题。我相信我已经使用了下面正确的设计模式。消费者: lock the mutex while the condition is not satisfied
我是一名优秀的程序员,十分优秀!