如何正确处理带有循环的互斥锁?

时间:2014-07-10 14:14:58

标签: c++ multithreading loops mutex

这是一个主要的理论问题,所以请不要反对我提出这个问题。

现在,我已经读到递归的互斥体是邪恶的。我明白了。

但是假设你有这种情况:

LockMutex();
for(ListIterator it = List.begin(); it != List.end(); ++it) {
    //doStuff, which might possibly alter the List contents
}
UnlockMutex();

很多人都很熟悉,我确定。 现在最大的问题是,如何正确处理这种情况?

在考虑它并且不使用递归互斥(这是邪恶的)之后,唯一可能的选择是做这样的事情:

LockMutex();
for(ListIterator it = List.begin(); it != List.end(); ++it) {
    UnlockMutex();
    //doStuff, which might possibly alter the List contents
    LockMutex();
}
UnlockMutex();

现在,递归互斥体的一个原因是邪恶的'是的,它们需要额外的开销才能记住谁拥有锁定以及它被锁定的频率......并且在每次迭代中解锁和重新锁定互斥锁都没有额外的开销?

此外,如果另一个线程在互斥锁解锁时访问列表并更改此迭代所在的元素,那么会发生什么?可能会删除我们当前所处的元素,实际上使迭代器无效,导致一个非常讨厌的错误?

我知道通过在迭代期间锁定整个列表是一个可怕的瓶颈,但我认为对于大多数轻量级应用程序来说,与我的风险相比,我能够忍受的是通过允许第二个线程在我不看的时候弄乱列表来崩溃整个应用程序。

我也看过ReaderWriter-Locks,但问题依然存在。 从技术上讲,只要循环的内容可能改变列表(很难预见,特别是如果你正在使用多态),你需要获得列表的写锁定,这也是意味着,当时没有其他线程可以访问该列表。并且迭代器失效的问题仍然存在。

所以是的,对我来说,有任何智慧的想法或话语吗?

1 个答案:

答案 0 :(得分:2)

  

// doStuff,可能会改变List内容

这意味着您的迭代器也可能不再有效。因此,我认为设置互斥锁是您上下文中的第二个问题。

是的,如果您可以使用有效的迭代器遍历列表,则必须保护完整列表,如果外部访问将以使迭代器无效的方式修改列表。我相信你不能保证对列表的外部访问会使你的迭代器有效。如此:互斥锁必须在你的循环周围。

但首先你应该记住,你对mutex保护循环中列表的访问必须保持迭代器的有效。