0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<h2>Как программист ошибку искал</h2>
1
<h2>Как программист ошибку искал</h2>
2
<p>Теги: sleep_for, sleep_until, std::this_thread::sleep_for, visual studio, steady_clock, system_clock, is_steady, c++, ожидание события</p>
2
<p>Теги: sleep_for, sleep_until, std::this_thread::sleep_for, visual studio, steady_clock, system_clock, is_steady, c++, ожидание события</p>
3
<h2>Один день из жизни команды разработчиков</h2>
3
<h2>Один день из жизни команды разработчиков</h2>
4
<p><i>"Слипы в коде - это очень и очень плохо!"</i>- разорялся программист Вася на совещании.<i>"Согласен, но давай пока так оставим?"</i>- робко парировал его коллега Антон.<i>"Лааадно, ты прав. Так действительно проще."</i>- нехотя согласился Вася.</p>
4
<p><i>"Слипы в коде - это очень и очень плохо!"</i>- разорялся программист Вася на совещании.<i>"Согласен, но давай пока так оставим?"</i>- робко парировал его коллега Антон.<i>"Лааадно, ты прав. Так действительно проще."</i>- нехотя согласился Вася.</p>
5
Возможно, вы считаете использование в коде конструкций типа или свидетельством отсутствия некоторых компетенций программиста. Это выбор каждого - использовать или не использовать какие-либо конструкции в языке (исключение - goto, его использовать вообще нельзя).<h2>Наглядный пример</h2>
5
Возможно, вы считаете использование в коде конструкций типа или свидетельством отсутствия некоторых компетенций программиста. Это выбор каждого - использовать или не использовать какие-либо конструкции в языке (исключение - goto, его использовать вообще нельзя).<h2>Наглядный пример</h2>
6
Однажды для решения задачи программист Антон использовал<b>sleep_for</b>. Код ожидания какого-то очень нужного события выглядел примерно вот так: while(!something_happened) std::this_thread::sleep_for(std::chrono::milliseconds(100)); Код прошёл ревью, тестирование и стал частью релиза. Этот код являлся частью довольно важного для продукта модуля. Спустя некоторое время поступила жалоба от заказчика, что этот модуль периодически стал зависать. Помогал только полный перезапуск всего продукта, что заказчика, конечно же, не особо радовало. Проблема возникала спонтанно, видимых связей с реальностью не было никаких (в общем-то как всегда). Спустя довольно долгое тестирование и изучение хитростей работы с отладчиком никакого прогресса в решении проблемы у Антона (по "счастливой" случайности задачу на этот баг дали ему) не появилось. И вдруг удача - баг удалось воспроизвести! Отладчик показал, что основной поток проблемного модуля завис на строчке 2 из приведённого выше кода. Причём, завис намертво, а вовсе не на 100 миллисекунд, как планировалось.<h2>Что же произошло?</h2>
6
Однажды для решения задачи программист Антон использовал<b>sleep_for</b>. Код ожидания какого-то очень нужного события выглядел примерно вот так: while(!something_happened) std::this_thread::sleep_for(std::chrono::milliseconds(100)); Код прошёл ревью, тестирование и стал частью релиза. Этот код являлся частью довольно важного для продукта модуля. Спустя некоторое время поступила жалоба от заказчика, что этот модуль периодически стал зависать. Помогал только полный перезапуск всего продукта, что заказчика, конечно же, не особо радовало. Проблема возникала спонтанно, видимых связей с реальностью не было никаких (в общем-то как всегда). Спустя довольно долгое тестирование и изучение хитростей работы с отладчиком никакого прогресса в решении проблемы у Антона (по "счастливой" случайности задачу на этот баг дали ему) не появилось. И вдруг удача - баг удалось воспроизвести! Отладчик показал, что основной поток проблемного модуля завис на строчке 2 из приведённого выше кода. Причём, завис намертво, а вовсе не на 100 миллисекунд, как планировалось.<h2>Что же произошло?</h2>
7
Первым делом, конечно же, Антон пошёл читать документацию стандартной библиотеки, а конкретнее, вызов<b>std::this_thread::sleep_for</b>: вдруг чего забыл сделать или флаг какой выставить? Оказалось, всё верно: просто передаёшь интервал времени и радуешься, никаких дополнительных настроек или флагов. Следующим шагом стало изучение реализации функции<b>sleep_for</b>в Visual Studio 2015 (именно этой средой и пользовались для сборки проекта). И именно этот шаг оказался решающим в поиске причин возникшего бага. Оказалось, что<b>sleep_for</b>реализован через<b>sleep_until</b>, и в качестве часов использовались не<b>steady_clock</b>, а обычные<b>system_clock</b>. Набрав тестовый пример с проверкой члена<b>is_steady</b>, наш герой убедился, что часы, которые используются для функции<b>sleep_for</b>являются чувствительными к подведению. Простой тест показал, что, если в момент выполнения строчки кода под номером 2 успеть перевести часы, к примеру, на полчаса назад, то и ждать поток будет не запланированные 100 миллисекунды, а целых полчаса. Если подвести часы не назад, а вперёд, то ситуация станет ещё плачевнее - поток никогда так и не проснётся. Если вам это кажется неправильным, то так оно и есть - такое поведение вызывает вопросы не только у вас. Судя по этому багу, проблема до сих пор не исправлена:<a>ПРУФ</a><i>P.S. Приведённая выше история является вымышленной, все совпадения событий и действующих лиц случайны.</i>
7
Первым делом, конечно же, Антон пошёл читать документацию стандартной библиотеки, а конкретнее, вызов<b>std::this_thread::sleep_for</b>: вдруг чего забыл сделать или флаг какой выставить? Оказалось, всё верно: просто передаёшь интервал времени и радуешься, никаких дополнительных настроек или флагов. Следующим шагом стало изучение реализации функции<b>sleep_for</b>в Visual Studio 2015 (именно этой средой и пользовались для сборки проекта). И именно этот шаг оказался решающим в поиске причин возникшего бага. Оказалось, что<b>sleep_for</b>реализован через<b>sleep_until</b>, и в качестве часов использовались не<b>steady_clock</b>, а обычные<b>system_clock</b>. Набрав тестовый пример с проверкой члена<b>is_steady</b>, наш герой убедился, что часы, которые используются для функции<b>sleep_for</b>являются чувствительными к подведению. Простой тест показал, что, если в момент выполнения строчки кода под номером 2 успеть перевести часы, к примеру, на полчаса назад, то и ждать поток будет не запланированные 100 миллисекунды, а целых полчаса. Если подвести часы не назад, а вперёд, то ситуация станет ещё плачевнее - поток никогда так и не проснётся. Если вам это кажется неправильным, то так оно и есть - такое поведение вызывает вопросы не только у вас. Судя по этому багу, проблема до сих пор не исправлена:<a>ПРУФ</a><i>P.S. Приведённая выше история является вымышленной, все совпадения событий и действующих лиц случайны.</i>