Вы правы, другой поток может вызвать putMVar main
и испортить putSkipChan
.Но модуль, создающий вышеуказанный код, не будет экспортировать конструктор SkipChan
, поэтому такая мошенническая операция будет невозможна.
dupSkipChan
делает new emptyMVar
называется sem
и добавляет это в список в основном.Он не добавляет ранее существовавший, созданный в newSkipChan
.Таким образом, здесь нет блока.
Чтобы объяснить больше другим читателям этого вопроса и комментария: Идея состоит в том, что может быть несколько потоков читателей.Изначально SkipChan main sem1
является единственным таким читателем.dupSkipChan
составляет SkipChan main sem2
.Если есть тысячи читателей, то вы не захотите уведомлять всех их о новом значении в putSkipChan
, поэтому конструкция такова, что getSkipChan
помещает свою семью в список main.Инициализация SkipChan
, как это делается в newSkipChan
и dupSkipChan
, также включает добавление нового пустого sem
в список main.
Вышеуказанная инициализация и дизайн означают, что первый getSkipChan
получает наибольшеепоследнее прошедшее значение было записано (или заблокировано для получения первого значения).Будущее getSkipChan
для этого SkipChan
всегда получит более новое значение, чем любое, полученное ранее, и не будет блокироваться, если это значение уже доступно.