Deadlock for free или почему нельзя делать suspend потокам

Сегодня коллега напоролся на дамп программы, которая зависла. Такое бывает, но когда затык происходит на int* pInt = new int, Штирлицу положено насторожиться.

Налицо deadlock, но прикол в том, что в коде никакой синхронизации в принципе нет вообще. Зато была приаттачена куча всяких bounds-checker’ов вкупе с отладчиками, что заставило меня вспомнить, что я когда-то где-то читал о том, что  неосторожное обращение с менеджером памяти может привести к дедлоку.

На самом деле, неосторожно обратиться с менеджером памяти достаточно сложно, но, как это обычно бывает, компьютер сделает все, что Вы ему скажете, но никто не обещает, что это будет то, что имелось в виду.

Так вот, интернет уже неоднократно объяснил, что делать suspend потоку извне – очень, очень плохая идея. Есть миллиард объяснений, почему, но все они сводятся к общему знаменателю – поток сам распоряжается своими ресурсами и поэтому должен сам контроллировать свое поведение. Даже если на первый взгляд поток не использует никаких разделяемых ресурсов, при более пристальном рассмотрении это может оказаться совсем не так.

Любой поток делит как минимум один ресурс с остальными потоками. Оперативную память. Распределение памяти контроллирует менеджер памяти, который, как правило, общий для всех потоков, в определенных рамках, конечно. Соответственно, есть очень неплохие шансы, что при процедура выделения памяти синхронизирована внутри менеджера памяти, грубо говоря, менеджер имеет mutex внутри. А дальше все просто – Вася запустил поток, поток радостно поскакал по инструкциями и весело побежал за оперативкой. Менеджер памяти залочил было мютекс, а тут Вася бац! Suspend потоку! И тут же в другом потоке начинает ломиться к тому же самому менеджеру памяти, которому пофиг, ибо мютекс зажат другим потоком. И, заметьте, совершенно бесплатно приходит им всем, включая Васю, первый, второй поток и менеджер памяти злой дед лок.

Конечно, это довольно грубая картина и в реальности все может быть несколько иначе, но суть от этого не меняется – приостановка потока извне – верный способ рано или поздно нарваться на deadlock.

Что не так в TFS.

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

Сразу отмечу, что я в основном использовал в своей работе CVS и Subversion, а также немного потыкал палочкой VSS, чтобы убедиться, что он и правда мертв, посему некоторые приколы, которые я упоминаю, могут быть и не проблемами вовсе. Так, дело привычки.

Ну, обо всем по порядку.

Закон Мерфи

Вот стоит какую-нибудь “очень простую” фигню, в которой “ну никак нельзя накосячить”, не покрыть юнит-тестом, как из этой простейшей фигни отрастают такие грабли, что трое опытных программеров вынуждены тратить целый день, чтобы этот косяк найти.

Не зря я тестирую даже “хелловорлды”, не зря.

В код мне баги! (С)

Готовимся к релизу продукта.

Так получилось, что я присоединился к команде где-то на середине процесса разработки и сразу огнем и мечом пинками ввел практику юнит-тестирования кода.

Сейчас функциональный код завершен полностью, настало время тестерам оторваться. Что получается? Правильно, 99% найденных багов – в коде, который был написан до моего прихода, то есть не был покрыт юнит-тестами.

(Оставшийся процент багов относится к различиям в формулировке ТЗ и тем, что на самом деле имелось в виду).

…тот в цирке не смеется.

Читаю спецификацию к одному очень промышленному формату. Спецификация солидная, 114 страниц, на двух языках. На 15 странице натыкаюсь на буквально следующее:

binary data
data organized in the form of bytes
NOTE The 8 bits in a byte can be organized in 256 different combinations. They can be used, therefore, to
represent the numbers from 0 to 255. If larger numbers are needed, several bytes can be used to represent a single
number, e.g., 2 bytes (16 bits) can represent the numbers from 0 to 65535. When the bytes are interpreted in this
fashion, they are known as binary data. Several different formats are in common use for storage of numeric data in
binary form.

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

Кстати, если вымарать весь подобный идиотизм оттуда, то описание формата влезло бы на половинку листа А4. Но за такой несолидный манускрипт денег брать, наверное, не получится :)

Там еще два абзаца о битах есть.

Первая заповедь программиста

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

8 visitors online now
8 guests, 0 members
Max visitors today: 15 at 09:10 am MST
This month: 23 at 05-03-2012 08:23 am MST
This year: 29 at 01-23-2012 02:50 am MST
All time: 45 at 02-23-2011 09:11 am MST