使用细粒度方法线程安全地删除链表节点

2023-12-03

为什么以下删除链表中节点的代码片段不是线程安全的?

编辑:注意每个节点都有自己的锁

// ... lock acquisition here
// ... assumption found to be valid here
prev->next = p->next;
p->next = NULL;
p->deleted = 1;

我假设您正在谈论单链表,因为您从未在节点删除中分配“prev”。给定一个单链节点列表,每个节点都受锁保护,它可能如下所示:

Head ==> A ==> B ==> C ==> D ==> Tail
               ^     ^
               |     |
        Thread 1     Thread 2

假设线程 1 将要删除节点 B。巧合的是,线程 2 将尝试同时删除节点 C。您给出的步骤可能会按如下方式执行:

Thread 1                Thread 2
----------------------  ----------------------
Lock B                  Lock C
A->next = C or D; <=??  B->next = D;    <== B could be dead already
B->next = NULL;         C->next = NULL;
B->deleted = 1;         C->deleted = 1;
Unlock B                Unlock C

在这种情况下,结果是不可预测的。如果线程 2 稍早于线程 1 执行,那么一切都应该没问题。线程 1 的第二行将执行“A->next = D”,因为线程 2 已经将 B->next 更改为 D。但是,如果线程 1 稍早于线程 2 执行,则 A->next 指向死节点 C ,死亡节点B被修改,节点D丢失。

因此,您可能会尝试锁定要删除的节点,然后在修改之前锁定“prev”。这些步骤可能执行如下:

Thread 1                Thread 2
----------------------  ----------------------
Lock B                  Lock C
Lock A                  waiting for B
A->next = C;            waiting for B
Unlock A                waiting for B
B->next = NULL;         waiting for B
B->deleted = 1;         waiting for B
Unlock B                Lock B         <= locking dead node
                        B->next = D;   <= assigning to dead node
                        Unlock B
                        C->next = NULL;
                        C->deleted = 1;
                        Unlock C

所以,这仍然不是线程安全的。 A->next指向死节点C,死节点B被锁定并使用,D丢失。我们所做的就是确保上述错误情况可靠地发生。

这里的解决方案似乎需要锁定“prev”before锁定要删除的节点。

Thread 1                Thread 2
----------------------  ----------------------
Lock A                  Lock B
waiting for B           Lock C
waiting for B           B->next = D;
Lock B                  Unlock B  
A->next = D;            C->next = NULL;
Unlock A                C->deleted = 1;
B->next = NULL;         Unlock C
B->deleted = 1;         
Unlock B                

A->next指向D,现在B和C都被删除了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用细粒度方法线程安全地删除链表节点 的相关文章

  • 在使用 stop_token 等待条件变量_any 时是否需要拥有锁来请求停止?

    在等待条件变量时 更改谓词状态的线程必须拥有锁 因此在唤醒期间不会错过更新 根据文档 这是必要的 即使在使用原子变量时也是如此 不过我不确定是否request stop 已经正确处理了 那么问题是 这两个选项中哪一个是正确且符合标准的呢 j
  • 设置一个值来指示线程已完成安全吗?

    我想将一个耗时的进程委托给我的 C 程序中的一个单独的线程 使用 boost 库 我编写了如下代码 thrd new boost thread boost bind myclass mymethod this finished flag W
  • 通过不同的线程使用多个 ORB(多线程多 Orb 客户端应用程序) - 如何?

    This question is related to Is it possible to have several ORB objects in the same process https stackoverflow com quest
  • 使用 MinGW gcc 4.4.0 增强 thread_interrupted 异常终止(),使用 3.4.5 则正常

    今天我一直在 玩弄 boost 线程作为学习练习 并且我有一个几个月前构建的工作示例 在我被打断并不得不暂时放弃多线程之前 它显示了不寻常的行为 当我最初编写它时 我使用的是 MingW gcc 3 4 5 并且它有效 现在我正在使用 4
  • 发布/订阅架构

    我尝试编写一个发布 订阅系统 客户端和服务器端 其中客户端接收定期更新 如心跳 消息控制 并可以向服务器发出命令 订阅某些源 这样做的好方法是什么 我已经有一个实现线程池的服务器来管理传入的客户端连接 我想知道如何处理连接双方都可以在 Ne
  • C++并行std::sort用于浮点值

    我有一个包含数百万个浮点值的大文件 我可以使用轻松对它们进行排序std sort通过将文件读入vector现在 例如 std vector
  • OpenMP 与浮点范围并行

    我有以下程序 int main double sum 0 pragma omp parallel for reduction sum for double x 0 x lt 10 x 0 1 sum x x 当我编译它时 我收到错误inva
  • 类和互斥体

    假设我有一个类代表一些名为 foo 的数据结构 class foo public foo attr01 0 void f attr01 5 private int attr01 class fooSingleThreadUserClass
  • 具有阻塞功能的 Twisted LoopingCall

    我有一个应用程序需要轮询数据库以了解可能的配置更改 该应用程序是一个使用 Twisted 的简单 xmlrpc 服务器 我尝试过使用Twisted的LoopingCall来执行轮询 但是由于LoopingCall在主线程上运行 所以对db的
  • Android SurfaceView 使用线程绘制画布

    我正在尝试使用线程在画布上绘图来创建一个简单的游戏引擎 但我遇到了一些无法解释的奇怪问题 这个 游戏 的目的是每秒在画布上画一个圆圈 这是可行的 但不是我想要的工作方式 似乎应用程序正在两个画布之间切换 并向每个画布添加一个圆圈 这样您就可
  • Shared_ptr 线程安全的开销是多少?

    std shared ptr保证是线程安全的 我不知道典型的实现使用什么机制来确保这一点 但肯定它必须有一些开销 即使您的应用程序是单线程的 这种开销也会存在 是上述情况吗 如果是这样 如果您不使用线程安全保证 这是否意味着它违反了 您不为
  • 在 Python 中共享多处理内存的更好方法?

    我已经解决这个问题一周了 它变得非常令人沮丧 因为每次我实现一个更简单但相似规模的示例来说明我需要做的事情时 事实证明多重处理都会把它搞砸 它处理共享内存的方式让我感到困惑 因为它非常有限 很快就会变得无用 所以我的问题的基本描述是 我需要
  • 有哪些学习线程编程的好资源? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 随着多核CPU在桌面上的兴起 多线程技能将成为程序员的宝贵资产 您能为想要学习线程编程的程序员推荐一些好的资源 书籍 教程 网站等 吗 看
  • 线程安全的异步字节队列

    我有一个回调方法 只要有新数据可用 就会调用该方法 public delegate void DataCallback byte buffer int offset int count 我想将其包装在一个实现与此类似的接口的类中 publi
  • 将 Python 控制台集成到 GUI C++ 应用程序中

    I m going to add a python console widget into a C GUI below some other controls 许多类将暴露给 python 代码 包括一些对 GUI 的访问 也许我会考虑 P
  • 带等待/通知的同步块与不带等待/通知的同步块之间的区别?

    如果我只是使用synchronized 不是wait notify方法 它仍然是线程安全的吗 有什么不同 Using synchronized使方法 块一次只能由一个线程访问 所以 是的 它是线程安全的 这两个概念是结合在一起的 而不是相互
  • Hazelcast 分布式锁与 iMap

    我们目前使用 Hazelcast 3 1 5 我有一个简单的分布式锁定机制 应该可以跨多个 JVM 节点提供线程安全性 代码非常简单 private static HazelcastInstance hInst getHazelcastIn
  • 缓冲后台输入流实现

    我已经写了背景InputStream and OutputStream 包装其他流并在后台线程上预读的实现 主要允许在处理解压缩流的不同线程中进行解压缩 压缩 这是一个相当标准的生产者 消费者模型 这似乎是一种利用多核 CPU 的简单方法
  • Interlocked.CompareExchange 的返回值是否有一些充分的理由

    The Interlocked CompareExchange 方法 docs https learn microsoft com en us dotnet api system threading interlocked comparee
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在

随机推荐