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

How do handle a mutex with a loop correctly?

本文关键字:循环 正确处理      更新时间:2023-10-16

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

现在,我读到递归互斥锁是邪恶的。我知道为什么。

然而,假设你有这样的小情况:

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,但问题仍然是一样的。从技术上讲,只要循环的内容可能改变列表(这很难预见,特别是在使用多态性的情况下),就需要获得对列表的写锁,这再次意味着,此时没有其他线程可以访问列表。并且迭代器失效的问题仍然存在。

所以,是的,有什么想法或智慧的话给我吗?

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

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

是的,如果你可以用一个有效的迭代器遍历列表,那么如果外部访问会以一种使迭代器无效的方式修改列表,你就必须保护完整的列表。我相信您不能保证对列表的外部访问将使您的迭代器保持有效。互斥锁必须在你的循环中。

但是首先要记住,在互斥锁保护的循环中访问列表必须保证迭代器的有效性。