双向链接的线程安全分离

Thread safe detachement of bidirectional link

本文关键字:安全 分离 线程 链接      更新时间:2023-10-16

我有两个对象,A和B,它们有一个指向彼此的指针。对象A可以由一个线程删除,而对象B可以由另一个线程来删除。删除对象A或B时,远程指针应设置为NULL(清除双向链接)。如何以安全的方式实现此功能?

虽然描述起来很简单,但我觉得实现起来并不容易。天真的想法是用互斥锁来保护每个指针。但是为了避免死锁,两个互斥锁必须按相同的顺序锁定。这需要一个对象首先锁定远程互斥。但这意味着以不受保护的方式使用指针来访问远程锁。

到目前为止,我找到的唯一解决方案是使用两个对象通过智能指针引用的一个共享互斥体。当两个对象都被销毁时,互斥对象也被销毁。单个互斥体保护对双向链路的访问。因此,一次只有一个线程可以修改双向链接并清除它

有更好的方法吗?

编辑:用例的详细信息

数据结构:

 ______          _____           _____          ______
|      | 1   N  |     |  1   1  |     |  N   1 |      |
|  A'  | -----> |  A  | <-----> |  B  | <----- |  B'  |
|______|        |_____|         |_____|        |______|
Thread_A                                         thread_B

A'由Thread_A完全控制,B'由Thread_B完全控制。B'和Thread_B在一个库中,我无法更改。但是B是用我提供给库的工厂方法构造的。所以我完全控制了B.的实施

Thread_B可以在任何时候删除B。因此,我无法控制B.Thread_A将在删除A'之前关闭库。这意味着Thread_B在Thread_A删除A'之前删除所有B和B'对象。Thread_A定期扫描A的列表,并用指向B的NULL指针擦除A。

运行时,数据必须以这种方式传输A'->A->B->B'。线程_A将数据存储在队列中,线程_B将数据从队列中取出。我决定将队列放在B中,因为Thread_A将数据存储在队列中是一个非阻塞操作。如果队列已满,则丢弃数据。当Thread_B试图从队列中提取数据时,它可能会碰到一个空队列。库实现者要求Thread_B最多等待1秒并返回。

因此,我需要一种保护来确保双向链路状态的清除和测试,并在Thread_a将其数据存储在B中的队列中时阻止删除B。

通过与@Slava、@SergeyA和@DanielStrul的评论进行了非常有益的讨论,迫使我完善了问题分析和描述,我终于找到了解决方案。

对象A总是在B之后被删除。所以我可以在A中存储一个互斥对象,这样Thread_A和Thread_B就可以在它上安全地同步

我不能使用weak_ptr,因为B的寿命不是用smart_ptr控制的。B’持有一个指向B的原始指针,Thread_B调用CCD_ 1。使用互斥锁,双向链接可以用原始指针来实现。

第一个强制性警告:

正如评论中所涵盖的,通过更清楚地分离生命周期和访问问题,可能有一种更清洁的方法来解决您正在解决的任何问题。

然而,如果你决心这样做,答案是std::lock(...)

http://en.cppreference.com/w/cpp/thread/lock