Рекурсивное блокирование мьютекса, знакомимся с std::recursive_mutex.

Всем привет! Случайно вспомнил, что мой блог про программирование, математику ващет и в целом создан для просвещения мешков с костями и мясом.

Поэтому хочу рассказать про 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!

Знакомимся с полезными инструментами STL — std::remove() и std::remove_if()

Добрый день, всем привет!

Снова в эфире рубрика «Вы не спрашивали, но мы отвечаем», раздел «Программирование», глава «Что нового я узнал в сейчас лет».

Например, не так давно я узнал, что std::unordered_map не сортирует данные в отличие от std::map. А много-много лет назад (в 2007-м году) нам пришлось реализовывать бинарный поиск, чтобы ускорить вставку элементов в std::map (там жил кэш текстур) вместо того, чтобы взять std::unordered_map. Наш просчёт немного оправдывает то, что мы были молоды, неопытны и std::unordered_map появился спустя пять с лишним лет после описываемых событий.

Вообще, я не отношусь к тем людям, которые ежедневно читают свежайший стандарт C++, подчеркивая карандашиком важные места. Скорее, я начинаю читать стандарт, когда нужно найти решение текущей задачи. Так, например, я совершенно случайно наткнулся на std::enable_shared_from_this, когда просматривал код нашего проекта, поминая тимлида нехорошими словами . Там был метод типа make() у класса, который должен вернуть std::shared_ptr от экземпляра этого класса. Если вы наследуете класс от std::enable_shared_from_this, то у вас появляется метод shared_from_this(), и дело в шляпе. Поскольку это было пять лет назад, уже не помню всех подробностей, но сначала было не очень, а потом резко стало хорошо! )

Каких-то одиннадцать лет назад я написал статью про эффективное удаление элементов массива. Тогда единственный способ, который я знал, выглядел следующим образом:

auto iter=data.begin()
while(iter != data.end()) {
    if (condition(*iter)) {
        iter = puf(data, iter);
    else {
        ++iter;
    }
}

Вся упомянутая в статье магия с перемещением в конец массива и удалением происходит в puf(). ЗдОрово, правда?

Оказывается, есть метод лучше, и имя ему — std::remove_if(), а самый интересный момент, что этот метод не удаляет элементы, а перемещает их в конец массива, возвращая итератор на начало этого кладбища погибших элементов. Между прочим, эксперимент показал, что после итератора лежит мусор.

С новыми знаниями, удаление элементов из контейнера будет выглядеть так:

auto iter = std::remove_if(data.begin(), data.end(), condition);
data.erase(iter, iter.end());

Что является более продвинутым вариантом и пишется короче, с чем я вас и поздравляю!

Фунция std::remove_if() удаляет элементы, для которых условие истинно, а std::remove() удаляет элементы с конкретным значением.

Где размять мозги программисту? Тренировочный полигон для айтишников

Всем привет! В этот раз расскажу, чем меряться программистам после кружки пива. Вот есть бегун, очевидно, что лучший бегун бежит или быстрее всех, или дальше всех. Или вот стрелок. Лучший конечно же тот, который чаще всего попадает в центр мишени, чем вне её.

А программистам и похвастаться нечем. Они не бегают и стрелять не умеют, а сидят сгорбленные, уставившись красными глазами в монитор и что-то пишут. Чем он занят? Зачем он здесь? Никто не знает.

А работодатель хочет знать как определить сильного программиста. По хиленьким ручкам, красным глазкам, горбатой спине или катышкам на свитере? Ну, допустим, текущему работодателю определить просто — надо брать того, кто не слишком сильно пахнет, а как быть с новым работодателем?

Вот пришёл ты такой красивый на собес и тебе прямо с порога — давай сортировку пузырьком пиши в уме! А ты работаешь в своём НИИ уже пятый десяток и всегда использовал метод sort() из вашей секретной сверхбыстрой библиотеки на Фортране и знать не знаешь что у неё внутри. И библиотека та написана учёным седовласым мужем, чьё имя с отчеством произносятся в конторе с придыханием и пиететом и бюст евоный стоит сразу при входе в холле. И значит это ровно то, что часть мозга, которая отвечает за простейшие алгоритмы атрофировалась за ненадобностью. Потому что все эти вещи пишутся один раз и навсегда, а не каждый день, как полагает потенциальный работодатель. Посему надо держать себя в тонусе. И помогут нам в этом два сайта LeetCode и HackerRank. Оба сайта, в принципе, одинаковые, но работодателя больше возбуждает HackerRank почему-то. Может из-за названия?

Сайты представлют собой список задач разного уровня сложности и среду для решения этих задач. Если вы программист и вам скучно или если вы не программист и вам интересно чем программисты зарабатывают на жизнь, смело заходите на любой из этих сайтов и решайте задачи.

Кому интересно, мой профиль на LeetCode и HackerRank.

Онлайн книжка по неопределённому поведению C++

Всем привет!

Буду краток, товарищ поделился ссылкой (спасибо, Влад!) на труд другого умного товарища.
Эта книга пригодится каждому программисту C++: Путеводитель C++ программиста по неопределенному поведению.

Вопросы программистам С++ на собеседованиях. Часть вторая

Здравствуй, дорогой читатель, вот и родилась вторая часть моего шедевра девятилетней давности. Только теперь формат статьи поменялся — ответы я буду писать в свободное время в очень ленивом режиме, потому что работу я не ищу и вопросы передо мной стоят совершенно другие (например, хитромудрый рендеринг в текстуру), а свободного времени у меня немного, потому что я во время него обычно сплю и само собой мне лень. При появлении ответа на какой-нибудь пункт, я буду его выделять, а ответ прятать под катом. И, разумеется, я не знаю ответов на абсолютно все эти вопросы и меня это нисколько не смущает, потому что я милорд синьор рисёрч инженер, а не Си плюс плюс задрот.

Алгоритмы

  • LRU кеш ограниченного размера
  • Что такое хеш таблица
  • Сделать дерево поиска в отсортированном массиве
  • Структура с указателем на parent и надо найти наименьшего общего предка
  • Вывести матрицу по спирали внутрь
  • Убрать элементы нулевые элементы в std::vector
  • Развернуть односвязный список
  • Исходный список содержит цифры, конечный i-й элемент содержит произведение всех элементов кроме i-того в исходном списке
  • Рисование закрашенного треугольника

Программирование

  • Бесконечная рекурсивная функция (в какие моменты может произойти, как сделать)
  • Написать свой std::shared_ptr
  • Отличие структуры от класса
    Ответ
    По умолчанию все члены struct имеют видимость public, а classprivate. Наследование от struct по умолчанию public, от classprivate. В остальном никакой разницы.
  • Выравнивание, размер структуры
  • volatile и mutable
  • Что такое pure virtual call
  • Вызов виртуальных функций из конструктора и деструктора
  • Таблица виртуальных функций
  • Как работает dynamic_cast, static_cast, reinterptet_cast, const_cast. Что происходит в случае ошибки приведения типа, работа со ссылкой и указателем
  • В чем отличие ссылки от указателя
  • Многопоточность std::shared_ptr
  • Факториал итеративно, рекурсия, на шаблонах
Блог Евгения Жирнова