Всем привет! Случайно вспомнил, что мой блог про программирование, математику ващет и в целом создан для просвещения мешков с костями и мясом.
Поэтому хочу рассказать про std::recursive_mutex
. Он такой же, как и std::mutex
, но запоминает номер потока, из которого был заблокирован и вторую блокировку в том же потоке игнорирует. В моём случае был приблизительно такой код:
struct Item { ~Item() { getStorage().RemoveItem(otherItemId); getStorage().AddItem(newItem); } } using ItemPtr = std::shared_ptr<Item>; using ItemRef = const ItemPtr&; using ItemId = std::size_t; class Storage { public: ItemId AddItem(ItemRef item) { std::scoped_lock lock(m_itemsGuard); m_items.push_back(item); return m_items.size() - 1; } bool HasItem(ItemId id) { return m_items.size() < id; } void RemoveItem(ItemId id) { std::scoped_lock lock(m_itemsGuard); auto item = m_items.at(id); m_items.erase(m_items.begin() + id); item.reset(); // Тут повторно заходим в RemoveItem } private: std::vector<ItemPtr> m_items; std::recursive_mutex m_itemsGuard; }; void test() { Storage storage; auto itemId = storage.AddItem(std::make_shared<Item>()); storage.RemoveItem(itemId); // здесь проблема } |
Обратите внимание, что в деструкторе Item
есть обращение к методам Storage
, а там на каждое изменение массива стоит блокировка мьютекса. И оно попадет в вечный lock с std::mutex
. А на этом у меня всё. Enjoy!