- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在尝试调试基于 Linux-futex 和原子操作的锁定原语中的竞争条件导致死锁时遇到了可怕的时间。这是我正在使用的代码(与真实代码完全相同的逻辑,只是去掉了对与问题无关的数据结构的依赖):
int readers, writer, waiting;
void wrlock()
{
int cur;
while (atomic_swap(&writer, 1)) spin();
while ((cur=readers)) futex_wait(&readers, cur);
}
void wrunlock()
{
atomic_store(&writer, 0);
if (waiting) futex_wake(&writer, ALL);
}
void rdlock()
{
atomic_inc(&waiting);
for (;;) {
atomic_inc(&readers);
if (!writer) return;
atomic_dec(&readers);
futex_wait(&writer, 1);
}
}
void rdunlock()
{
atomic_dec(&waiting);
atomic_dec(&readers);
if (writer) futex_wake(&readers, ALL);
}
atomic_*
和 spin
函数非常明显。 Linux futex 操作是 futex_wait(int *mem, int val)
和 futex_wake(int *mem, int how_many_to_wake)
。
我遇到的死锁条件是 3 个线程,readers==0
,writer==1
,waiting==2
,以及等待 futex_wait
的所有线程。我不明白这是怎么发生的。
对于那些想因为我没有使用 pthread 基元而对我大吼大叫的人,请把它留到另一个问题。这是运行时不依赖于 glibc/libpthread 的低级代码。无论如何,我认为这个问题可能对其他人学习低级并发黑魔法有用,或者可能会吓到其他人远离尝试编写这样的代码......;-)
顺便说一句,硬件是 x86,所以即使代码存在内存排序问题,我也不认为它们会表现为错误。我猜我只是遗漏了对 futexes 的微妙误用,特别是因为当所有等待都被虚拟为自旋时,代码工作正常。
这是为 wrlock
生成的 asm(与我发布的版本基本相同,只是它为第一个自旋锁调用了一个单独的函数 lock
)。开头的附加条件返回是“如果我们没有运行多个线程,则退出”。 0x338
和0x33c
分别对应readers
和writer
。 call 1af
实际上是调用外部的futex_wait
的重定位。
00000184 <wrlock>:
184: a1 18 00 00 00 mov 0x18,%eax
189: 55 push %ebp
18a: 85 c0 test %eax,%eax
18c: 89 e5 mov %esp,%ebp
18e: 75 02 jne 192 <wrlock+0xe>
190: c9 leave
191: c3 ret
192: 68 3c 03 00 00 push $0x33c
197: e8 7e fe ff ff call 1a <lock>
19c: 58 pop %eax
19d: a1 38 03 00 00 mov 0x338,%eax
1a2: 85 c0 test %eax,%eax
1a4: 74 ea je 190 <wrlock+0xc>
1a6: 6a 01 push $0x1
1a8: 50 push %eax
1a9: 68 38 03 00 00 push $0x338
1ae: e8 fc ff ff ff call 1af <wrlock+0x2b>
1b3: a1 38 03 00 00 mov 0x338,%eax
1b8: 83 c4 0c add $0xc,%esp
1bb: 85 c0 test %eax,%eax
1bd: 75 e7 jne 1a6 <wrlock+0x22>
1bf: eb cf jmp 190 <wrlock+0xc>
最佳答案
我认为这说明了您的潜在僵局。假设单个处理器按以下顺序执行您的 3 个线程:
// to start,
// readers == 0, writer == 0, waiting == 0
Reader1
===================================
// in rdlock()
atomic_inc(&waiting);
for (;;) {
atomic_inc(&readers);
// if (!writer) has not been executed yet
// readers == 1, writer == 0, waiting == 1
writer
===================================
// in wrlock()
while (atomic_swap(&writer, 1)) spin();
while ((cur=readers)) futex_wait(&readers, cur)
// writer thread is waiting
// readers == 1, writer == 1, waiting == 1
// cur == 1
Reader1
===================================
// back to where it was in rdlock()
if (!writer) return;
atomic_dec(&readers);
futex_wait(&writer, 1);
// Reader1 is waiting
// readers == 0, writer == 1, waiting == 1
Reader2
===================================
// in rdlock()
atomic_inc(&waiting);
for (;;) {
atomic_inc(&readers);
if (!writer) return;
atomic_dec(&readers);
futex_wait(&writer, 1);
// Reader2 is waiting
// readers == 0, writer == 1, waiting == 2
现在你陷入了僵局。
当然,我可能不了解 futex API 是如何工作的(我从未使用过它们),所以如果我在这里偏离基地,请告诉我。我假设阻塞(因为预期值是正确的)的 futex_wait()
不会解除阻塞,直到对该地址的 futex_wake()
调用。
如果 atomic_xxx()
操作可以解除对 futex_wait()
的阻塞,则此分析不正确。
最后,如果这是发生在你身上的事情,我还没有机会考虑可能的解决方案......
关于c - 在使用原子和 futexes 锁定代码时无法找到竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4357183/
使用共享内存中存储的 rwlock 对象的同一进程中的两个线程在 pthreads 压力测试期间遇到崩溃。我花了一段时间试图找到内存损坏或死锁,但到目前为止一无所获。这只是通知我我造成了僵局的一种不太
futex man page提供了一个简单的演示,但我无法得到页面描述的结果,结果似乎在我的机器上死锁(linux 5.2.1);父进程不会被子进程唤醒。手册页是否错误? 我的机器上的输出示例: [r
我有一个futex的示例代码。但是我无法理解代码流程.... #include #include #include #include #include #define NUM 50 int
我正在尝试使用信号量解决哲学家就餐问题。哲学家先拿起左边的 fork ,然后拿起右边的 fork ,吃完后放下。我正在使用 5 个线程一个用于每个哲学家和 5 个信号量一个用于每根筷子来实现这一点。需
我们在 Linux RedHat 机器上观察到我们的一个 Java 应用程序在尝试发布到外部 MQ 队列时出现异常延迟(以前从未发生过)。对盒子进行了快速健康检查,CPU/内存使用情况似乎还不错。 M
有什么方法可以在 iOS 上实现快速自旋锁,当且仅当存在争用时恢复为阻塞操作系统原语?我正在寻找与这些实现等效的东西: http://locklessinc.com/articles/keyed_ev
不相关的进程如何使用 futex 进行协作? 假设我有不相关的进程,例如,一个是我的模块的 apache 子进程,另一个是例如一个后台脚本。 我想使用 futex 在两者之间建立一个带有互斥锁的条件变
我需要在锁定/解锁上下文之外的用户空间中调用 do_futex() 的功能。也就是说,我不需要互斥体,而是内核调用 do_futex 的确切语义。 它似乎应该在用户空间中可用,因为其目的是尽量减少系统
我有一个用 Haskell 编写的微服务。它使用斯科蒂。 LTS 是 13.20。操作系统:Linux 3.10.0-957.el7.x86_64,运行在Kubernetes下。该服务工作了大约 0.
我正在阅读一些文档并尝试一些发出 futex 的代码示例。 Linux 中的系统调用。我读到如果 thread_a 获得了互斥锁使用 FUTEX_LOCK_PI ,并说如果另一个线程 thread_b
我有一个在生产环境中运行的 Python 守护进程。它使用 7 到 120 个线程。最近最小的实例(7 个线程)开始出现挂起,而所有其他实例从未出现过此类问题。将 strace 附加到 python
这个方法(我意识到这个函数可能需要一些额外的参数): void waitUntilNotEqual(volatile int* addr, int value) { while (*addr
我正在尝试同步 5 个进程,它们必须由同一个父进程创建。 我尝试插入 5 个 waitpids 以等待子进程结束,但代码从未到达 D4 和 D5。 #include #include #inclu
我一直在对基于 futex 的锁使用服务员计数方法:与 futex int 相邻,有第二个 int,这是服务员竞争的服务员计数对于锁,在执行 futex 等待操作之前自动递增,并在从 futex 系统
有人可以告诉我一个使用基于 futex 的锁定机制的例子吗? (多核 x86 CPU,CentOS) 最佳答案 Pthreads 的互斥量是在最新版本的 Linux 上使用 futexes 实现的。
我在尝试调试基于 Linux-futex 和原子操作的锁定原语中的竞争条件导致死锁时遇到了可怕的时间。这是我正在使用的代码(与真实代码完全相同的逻辑,只是去掉了对与问题无关的数据结构的依赖): int
我有一个等待 futex 的进程: # strace -p 5538 Process 5538 attached - interrupt to quit futex(0x7f86c9ed6a0c, F
我在 64 位 Linux 机器上: Linux illin793 2.6.32-279.5.2.el6.x86_64 #1 SMP Tue Aug 14 11:36:39 EDT 2012 x86_
我正在尝试在 Linux 中使用基于健壮的 futex 的 pthread 互斥体,因为我需要既快速又健壮(恢复“死”锁)。我如何检查任何 Linux 系统上的 pthread 互斥库是否基于健壮的
我有一个 sqoop 命令,它使用 hcatalog 参数将数据从 Oracle 导入到 hive orc 表中。 sqoop import -D oraoop.disabled=true -D ma
我是一名优秀的程序员,十分优秀!