这个问题源于我通过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时,问题就出现了,因为我无法删除锁定的互斥体,但如果我解锁它,我就不能保证其他人可以访问正在删除的对象。(在我看来,锁定互斥锁的线程也应该有删除它的可能性)。
销毁应始终在外部同步。互斥锁(或任何本质上同步的对象)永远无法同步其自身的销毁。
您担心的竞争是,两个线程可能在同一个MailBox
对象上同时调用DeleteMailBox
和TxMailBox
。正如您所观察到的,MailBox
对象本身无法防止这种竞争。即使您可以破坏一个锁定的互斥体,另一个线程的并发锁定尝试现在也会试图锁定一个被破坏的互斥体——这是一场数据竞赛。
这是多线程环境中面向对象设计的基本限制。如果用户请求销毁一个对象,则由用户确保从那时起没有人会试图同时访问该对象。
请注意,在此上下文中,用户可以是任何外部实体。例如,在C++11中,您可以经常使用weak_ptr
来解决这个问题。但原则上,这仍然是一个非常重要的问题,需要仔细考虑。