Магистерский курс C++ (МФТИ, 2022-2023). Лекция 20. Очереди.

แชร์
ฝัง
  • เผยแพร่เมื่อ 18 ก.ย. 2024

ความคิดเห็น • 23

  • @kyberduk-youtube
    @kyberduk-youtube ปีที่แล้ว +6

    О последней задачке (что удалось увидеть сразу, может там еще что есть).
    Два консьюмера одновременно проходят safe_empty().
    Первый успевает сделать safe_pop().
    А вот второму достанется пустая очередь - safe_pop() и бум.

    • @tilir
      @tilir  ปีที่แล้ว +4

      Да тривиальный API race. Мои поздравления, отличная скорость решения ))

  • @tilir
    @tilir  ปีที่แล้ว +2

    Немного errata в отношении пока не замеченных в комментариях ошибок для bounded MPMC queue / stack.
    (1) В случае multi-producer делать wake_and_done надо на всех продьюсеров один раз иначе бывает так что консьюмеры повыходили но не все продьюсеры ещё закончили.
    (2) Саму функцию wait_and_pop надо делать с сигнатурой bool wait_and_pop(T &Data) чтобы понимать есть там что консьюмить или нет
    (3) Внутри wait_and_pop условие должно выглядеть так:
    CondCons.wait(Lk, [this] { return !empty() || done(); });
    if (empty())
    return false;
    Даже если у нас сигнализирован done, задачи могут быть недоразобраны и поэтому критерий return false это только empty.
    (4) Внутри push признак done вообще проверять не надо т.к. это признак отработки всех продьюсеров. Там играет роль только full.
    (5) В интерфейсе необходим метод is_empty_and_done() чтобы по нему консьюмеры понимали когда начинать выходить.
    Полу-финальные обновлённые версии bounded stack и bounded queue с тестами на то что они не теряют задач я выложил сюда:
    github.com/tilir/cpp-masters/blob/master/queues/classic_queue.cc
    github.com/tilir/cpp-masters/blob/master/queues/classic_stack.cc
    Начну с этого следующую лекцию.

    • @ana_infinite_games
      @ana_infinite_games ปีที่แล้ว

      Выходит, что метод is_empty_and_done - вводящий в заблуждение, т.к. зависит от того, действительно ли пользователь закончил пользоваться push'ами.
      И еще должен быть соблюден строгий гайдлайн:
      1) закончить push'ы и синхронизировать всех продюсеров
      2) вызвать wake_and_done
      3) только теперь сихронизировать консюмеров
      И даже после этого мы можем продолжать пользоваться и Push и Pop. Ибо флаг Done ограничивает только возможность засыпать у консьюмера)
      wake_and_done тоже нужно защитить мьютексом, саму переменную Done.
      И вот если из Push начать возвращать false, если Done уже стоит, то тогда is_empty_and_done уже не поменяется.

    • @igorlugansky7193
      @igorlugansky7193 ปีที่แล้ว

      А если поток задач бесконечен, то как будто бы (4) done в push будет полезен. Или задача на данном этапе звучит как MPMC и через нее пропустить гарантированно N задач?
      зы: Хотя я бы может извне сделал байпас на пуше для бесконечного потока задач, чтобы очередь на себя много не брала. Либо push возвращал бул, чтобы пользователь-продюсер мог понять, что пушить нельзя, и что-то с этим сделал. Не нравится в такой схеме, что о подобных событиях продюсер узнает от очереди.

    • @ana_infinite_games
      @ana_infinite_games ปีที่แล้ว

      Я вообще думал, что остатки из очередей единственно правильно консъюмить после остановки всех потоков перед непосредственным удалением очереди в месте владения очереди.

  • @РоманМитин-п4т
    @РоманМитин-п4т ปีที่แล้ว +6

    Мне кажется очередь с 15:00 является на самом деле стеком

    • @tilir
      @tilir  ปีที่แล้ว +2

      Спасибо за наблюдательность. Я действительно взял не тот пример. Впрочем bounded очередь не особо сложнее, но там нужно две позиции и разбирать с хвоста. Начну с этого следующую лекцию.
      Интересно что та же ошибка в курсе 2019-20 года осталась незамеченной на много лет (в т.ч. мной). Сильно растёт уровень аудитории...

  • @makaedg
    @makaedg ปีที่แล้ว +2

    Здравствуйте, Константин. Спасибо за интересную лекцию!
    На слайде 42 (1:13:33) не должно ли быть std::forward_as_tuple вместо std::make_tuple?

  • @АндрейШевелёв-г2щ
    @АндрейШевелёв-г2щ ปีที่แล้ว +3

    Здраствуйте, Константин. Хотел задать вопрос - будут ли выложены на ютуб лекции по языку С с первого курса? Очень хотелось бы увидеть на ютубе лекции по этому языку в вашем исполнении, уж слишком у вас шикарная манера подачи учебного материала)

    • @tilir
      @tilir  ปีที่แล้ว +6

      Я очень хочу их в каком то виде записать и выложить. Возможно следующий учебный год как раз на этом сконцентрируюсь.

    • @Robinzon__Kruzo
      @Robinzon__Kruzo ปีที่แล้ว +3

      @@tilir Спасибо за вашу работу, в одном из прошлых видео в комментариях еще спрашивали про курс ассемблера. Лично я очень жду и С, и ассемблер, надеюсь у вас все получится в следующем учебном году :)

    • @tilir
      @tilir  ปีที่แล้ว +6

      Это один и тот же курс. Странно учить одно без другого.

    • @АндрейШевелёв-г2щ
      @АндрейШевелёв-г2щ ปีที่แล้ว +2

      @@tilir да. Уже немало времени учу с++ самостоятельно (может года полтора, с перерывами) но чувствуются пробелы в знаниях, связанные с С и ассемблером. Надо, наверное, было начинать изучение с них. Но так уж сложилось) Поэтому очень-очень жду записи лекций первого курса. Ваши лекции лучшие!

  • @igorlugansky7193
    @igorlugansky7193 ปีที่แล้ว +3

    По unbounded_queue с 33-ей минуты есть вопрос.
    void wait_and_pop(T& Data) {
    ...
    Cond.wait(Lk, [this]{ return !Q.empty(); });
    T Task = std::move(Q.front()); // а это корректно в случае лимитера? у нас не будет лимитер moved-from после того
    // как первый из проснувшихся консюмеров его обработает?
    ...
    }
    Не правильнее ли будет сделать мув после проверки?
    void wait_and_pop(T& Data) {
    ...
    Cond.wait(Lk, [this]{ return !Q.empty(); });
    T& Task = Q.front();
    if (Task == Limiter) {
    ...
    }
    ...
    Data = std::move(Task);
    Q.pop();
    }

    • @tilir
      @tilir  ปีที่แล้ว +1

      Да интересное и тонкое замечание, спасибо. В этом примере роли не играет но в общем случае вы конечно правы.

    • @danielkeehl7450
      @danielkeehl7450 5 หลายเดือนก่อน

      Только хотел написать, как увидел что уже заметили)

  • @danielkeehl7450
    @danielkeehl7450 5 หลายเดือนก่อน

    32:09
    Почему мы делаем Q.wake_and_done() в consume? Мы точно знаем, что в produce он выполнится первым, и зачем-то пушим лимитеры второй раз. Или я что-то не так понял?

  • @ana_infinite_games
    @ana_infinite_games ปีที่แล้ว +1

    Честно не знаю насколько хорошо плавают котята, но надеюсь фраза "всплывают 3 белых котенка" не несет зловещего смысла)

  • @navy5400
    @navy5400 8 หลายเดือนก่อน

    Константин говорит о неком TLA который позволяет отследить, что многопоточный код работает верно. Речь об этом на 28 минуте. Можете кто нибудь поделится референсами на этот инструментарий ?

    • @tilir
      @tilir  8 หลายเดือนก่อน

      th-cam.com/video/_9B__0S21y8/w-d-xo.html

  • @dimon_ksi
    @dimon_ksi ปีที่แล้ว

    Мне кажется, что std::reference_wrapper можно принимать в функции просто by value

    • @tilir
      @tilir  ปีที่แล้ว

      Ну всё-таки там ссылочная семантика и хочется сохранить указание на это в параметрах.