这个问题源于我通过pthread实现以下简单的邮箱界面:
typedef void* MailBox;
typedef enum MailBoxReturnValues {ok=0, fail4timeOut, fail} MailBoxReturnValues;
MailBox CreateMailBox (const char* const mailBoxName); /* returns NULL 4 fail */
MailBoxReturnValues DeleteMailBox (MailBox mailBox);
MailBoxReturnValues TxMailBox (MailBox mbx, void* sendingObj, unsigned timeoutInTic);
MailBoxReturnValues RxMailBox (MailBox mbx, void* *receivingObj, unsigned timeoutInTic);
为了实现它,我创建了一个C ++类,其中我放置了所有的suff,还有一个互斥体,它必须序列化对每个实例的访问。当我尝试编写DeleteMailBox时,问题就出现了,因为我无法删除锁定的互斥锁,但如果我解锁它,我无法保证其他人可以访问删除对象。 (在我看来,锁定互斥锁的线程也必须有可能删除它。)
答案 0 :(得分:3)
销毁应始终在外部同步。互斥体(或任何本质上同步的对象)永远不能同步它自己的破坏。
您担心的竞争是两个线程可能同时在同一个DeleteMailBox
对象上调用TxMailBox
和MailBox
。正如您所观察到的,MailBox
对象本身无法防范此种族。即使你可以销毁一个锁定的互斥锁,另一个线程的并发锁定尝试现在会尝试锁定一个被破坏的互斥锁,这是一个数据竞争。
这是多线程上下文中面向对象设计的基本限制。如果用户请求销毁对象,则由用户确保没有人会尝试从该点开始同时访问该对象。
请注意,此上下文中的 user 可以是任何外部实体。例如,在C ++ 11中,您经常可以使用weak_ptr
来解决此问题。但原则上这仍然是一个非常重要的问题,需要仔细考虑。