Как искать критические секции в сложном и запутанном проекте?

237
17 апреля 2018, 04:15

Пишу многопоточное высоконагруженное клиент-серверное приложение на С++. В приложении чётко определены четыре основных потока и так-же во время работы могут создаваться короткоживущие дополнительные потоки. Ранее я писал многопоточные приложения на C# но они не были такими большим по количеству классов и методов. Недавно я нашёл нескольколько несинхронизированных вызовов методов одного из синглтонов и пытаясь это раскрутить я понял, что полностью утратил контроль над критическими секциями (т.е. я не понимаю какие участки кода в каких потоках у меня работают). Ситуацию усугубляет то что в проекте очень активно используются колбэк вызовы и отслеживать цепочки таких вызовов очень трудно. Вопрос в следующем, есть ли какие-нибудь методики отслеживания критических секций? Как поступаете вы, когда пишите очень сложные многопоточные приложения? Какие есть рекомендации что бы избежать таких ситуаций (что-то натипа SOLID для мультипоточного программирования =))?

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

UPD: Хотел добавить, что первое что мне пришло в голову это жёстко документировать каждый метод и каждое поле класса в каких потоках они могут вызываться и использоваться. Во-первых это огромная работа на которую придётся убить кучу времени, во вторых я очень сильно потеряю в гибкости, но другого выхода я пока не вижу. Кто-нибудь делал что-нибудь подобное в своих проектах?

Answer 1

Что помогает мне:

  1. Один мьютекс должен контролировать только данные того же объекта, но не шариться на несколько объектов, тем более несколько объектов разного класса.

  2. Везде использую только нерекурсивные мьютексы, т.к. намного легче контролировать область, защищенную мьютексом.

  3. В непубличные методы класса, которые сами не захватывают мьютекс, но должны работать только под ним, добавляю assert(m.try_lock() ? m.unlock(), false : true), если где-то неправильно вызвал, то сработает assert. Для визуального удобства такие методы заканчиваются на *Unsafe(...)

  4. Если по логике программы метод должен быть вызван только из определенного потока, то добавляю assert(currentThread() == m_specialThread);

  5. Никогда не вызывать внешние (которые мы локально не контролируем) callback'и, т.к. из них могут быть вызваны другие, а из них наши мьютексы, но в другом прядке и получим DEADLOCK. Кстати, тут пункт 2) очень помогает.

  6. Из любого правила если исключения, но это именно исключения и они обкладываются еще кучей ассертов и документируются в коде, почему так сделано.

READ ALSO
Проблема с чтением бинарных данных

Проблема с чтением бинарных данных

Всем приветВозникла проблема при чтении бинарных данных( *

195
Не работает обработчик ошибки 404 в node.js

Не работает обработчик ошибки 404 в node.js

Привет!Я учу nodejs и попутно создаю свой API сервер с MongoAtlas

196
Помощь в настройке роутинга на Ангулар2

Помощь в настройке роутинга на Ангулар2

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

210
Почему не правильно работает функция?

Почему не правильно работает функция?

Почему к примеру если указать "17:00","19:00" выведет правильно 7200000ms - то есть до oldtime 2ч

171