- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有趣的是,我发现很多程序员错误地认为“无锁”只是意味着“没有互斥锁的并发编程”。通常,还有一个相关的误解,即编写无锁代码的目的是为了更好的并发性能。当然,无锁的正确定义实际上是关于进度保证的。无锁算法保证至少一个线程能够向前推进,而不管其他线程在做什么。
这意味着无锁算法永远不会有一个线程依赖另一个线程才能继续的代码。例如,无锁代码不能出现线程 A 设置标志,然后线程 B 在等待线程 A 取消设置标志的同时不断循环的情况。像这样的代码基本上实现了一个锁(或者我称之为变相的互斥锁)。
然而,其他情况更微妙,在某些情况下,老实说,我无法真正判断算法是否符合无锁条件,因为“取得进步”的概念有时对我来说是主观的。
一个这样的案例是在(备受推崇的,afaik)并发库中,liblfds .我正在研究 liblfds 中多生产者/多消费者有界队列的实现 - 实现非常简单,但我无法确定它是否应该符合无锁条件。
相关算法在 lfds711_queue_bmm_enqueue.c
. Liblfds 使用自定义原子和内存屏障,但算法很简单,我可以用一段左右的时间来描述。
队列本身是一个有界连续数组(环形缓冲区)。有一个共享read_index
和 write_index
.队列中的每个槽都包含一个用户数据字段和一个 sequence_number
值,这基本上就像一个纪元计数器。 (这避免了 ABA 问题)。
PUSH算法如下:
write_index
write_index % queue_size
处保留队列中的一个插槽使用尝试设置 write_index
的 CompareAndSwap 循环至 write_index + 1
. sequence_index
在write_index + 1
. bool mcmp_queue::enqueue(void* data)
{
int write_index = m_write_index.load(std::memory_order_relaxed);
for (;;)
{
slot& s = m_slots[write_index % m_num_slots];
int sequence_number = s.sequence_number.load(std::memory_order_acquire);
int difference = sequence_number - write_index;
if (difference == 0)
{
if (m_write_index.compare_exchange_weak(
write_index,
write_index + 1,
std::memory_order_acq_rel
))
{
break;
}
}
if (difference < 0) return false; // queue is full
}
// Copy user-data and update sequence number
//
s.user_data = data;
s.sequence_number.store(write_index + 1, std::memory_order_release);
return true;
}
read_index
处的插槽中弹出一个元素。将无法这样做,直到它观察到插槽的
sequence_number
等于
read_index + 1
.
false
因为它认为队列是空的。我觉得这是否真的属于“取得进展”的定义是值得商榷的。
最佳答案
这个队列数据结构是不是 我认为最合理的定义是严格无锁的。该定义类似于:
A structure is lock-free if only if any thread can be indefinitely suspended at any point while still leaving the structure usable by the remaining threads.
m_write_increment
,但还没有写
s.sequence_number
使容器处于很快将无法使用的状态。如果这样的线程被杀死,容器最终会向
push
报告“满”和“空”。和
pop
分别违反了固定大小队列的约定。
m_write_index
和相关联的
s.sequence_number
的组合) - 但它基本上就像一个每个元素的互斥锁。因此,只有在您进行循环并且新的作者试图获取互斥锁时,写入者才会发现失败,但实际上,所有后续写入者实际上都未能将其元素插入队列,因为没有读者会看到它。
syscall
.
compare_exchange_weak
,以及一些可能昂贵的操作(
memory_order_acquire
加载和
memory_order_release
存储)1,其他开销很小。
std::mutex
类似这意味着类似于锁定的原子操作和解锁的另一个原子操作,实际上在 Linux 上,pthread 调用也具有不可忽略的开销。
m_write_index
变量由所有读者自动更新,这将是一个争论点,但只要底层硬件 CAS 实现是合理的,行为应该是合理的。
m_write_index
之间的临界区中被切出更新和序列号写入,其他线程可以继续
push
元素到队列中,只要它们没有从停顿的线程一直环绕到进行中的元素。线程也可以
pop
元素,但仅限于进行中的元素。
push
对于高容量队列,行为可能不是问题,
pop
行为可能是一个问题:如果与线程被上下文切换的平均时间相比,队列具有高吞吐量和平均填充度,则队列将很快对所有消费者线程显示为空,即使添加了许多元素超出了进行中的元素。这不受队列容量的影响,而只是受应用程序行为的影响。这意味着当发生这种情况时,消费者端可能会完全停止。在这方面,队列看起来根本不是无锁的!
push
队列中的一个元素(只有稍后通过使用线程才能看到)并且仍然可以
pop
队列中的一个元素。
关于c++ - 无锁进度保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45907210/
我正在开发一个在 gridview 中显示数据表内容的网页。而且,还有一个名为“发送到 Excel”的按钮。如果用户单击此按钮,该程序将开始生成报告(将数据表内容写入 excel 文件)。完成后,会出
理论:我在开始时做出了大约 100 个 promise ,然后使用 Promise.all() 解决它们。 这 100 个 promise 中的每一个依次进行一些异步 REST 调用,其响应可能主要不
在将文件添加到 python 中的 tar 存档时,是否有任何库可以显示进度,或者可以扩展 tarfile 模块的功能来执行此操作? 在理想情况下,我想展示 tar 创建的总体进度以及关于何时完成的预
有没有办法在 Xcode 中更改进度 View 栏的高度? 我正在使用 Xcode 4.3 并且需要一个垂直进度条。我旋转了栏,但现在无法更改高度并且显示为一个圆圈。 还有一种更有效的旋转进度条的方法
您好,我想在栏按钮项上制作未确定的进度 View 。完成后我想让它隐藏,但 hidden() 方法没有像 disabled(Bool) 这样的参数。任务完成后如何隐藏进度 View ? 这就是我要的
我有一个管理员控制的功能(导入数据库)可能需要一些时间才能完成,所以我想在这段时间内向用户显示一些反馈 - 例如进度条,或者只是一些消息。即使在长时间的 Action 中分部分发送页面也足够了。 在
我是一个进步的菜鸟,实际上在基本 block 方面有问题。 下面的问题是在我的 if else 语句中。它在 if, then, else then 时工作正常,但是当我想将多个语句放入 if 部分时
我有一个来自 rsync 命令的日志文件,其中有进度。运行此进度时,会更新同一行上的显示信息。当我捕获此命令的输出时,我得到一个在终端上使用 cat 正常显示的文件(重播所有退格键和重新编辑)但我希望
我需要处理一些数据,每 5-10 秒显示一个进度(我以 % 显示进度,但我也更新了一些图表)。我想在没有多线程的情况下做到这一点。 循环可能相当大。它可以从数百万开始,可以高达数十亿。 我可以使用 G
我正在致力于使用 PHP、HTML 和 JavaScript 制作半直播互联网 channel 。 您可以在此处查看演示:http://mariocreative.host/chanelko/inde
我实际上正在使用图像为“点点点”进度设置动画。我想通过使用下面的代码来使用不透明度。 动画将持续 3 秒,有没有更简单的动画方法? 最佳答案 这是一个快速版本,它会在控
我写了这个程序,它返回用户插入的最大整数。现在,我希望程序返回第二大整数。我创建了一个新变量(称为“状态”),该变量应该在每次循环重复时增加 1 个单位。然后,在中断条件发生后,我将在状态变量中后退
我正在制作一个需要保存进度的java游戏。但我不想让外部文件保存进度(像《我的世界》这样的游戏有一个存储文件的“保存”目录)。所以基本上我希望它存储一些数据,当用户退出并再次返回时可以检索这些数据。比
我正在使用 forEach_root 方法在 Android 上计算图像。 RenderScript RS=RenderScript.create(context); Allocation inPix
我希望这个进度 View 在完成后基本上“重置”。 尝试将计数重置为 0,它确实重置了,但是对于每次重置,计时器只会变得越来越快。 .h @property (nonatomic, strong) N
我不确定这是否可能。当您单击“提交”按钮时,似乎有一种方法可以做到这一点。 private Button getButton(String id) { return new AjaxButto
我找不到关于如何在迭代循环时更新 UIProgressbar 进度的明确答案,例如: for (int i=0;i
我正在尝试在 Xcode 中翻转 UIProgressView 180,同时我正在尝试缩放进度 View 。在我添加翻转之前缩放效果很好,然后缩放不再起作用。有什么建议么?谢谢! [self.seco
我目前正在通过评估 prepareForSegue 中的 segue.identifier 动态加载新 View : - (void)prepareForSegue:(UIStoryboardSegu
当任意进程发生时,我需要在屏幕上为用户提供状态。我无法知道需要多长时间。我怎样才能永远增加 progressView (当它接近 1 时它会减慢)。 最佳答案 This如果您愿意更换进度 View ,
我是一名优秀的程序员,十分优秀!