Facebook представил (https://code.facebook.com/posts/293371094514305/open-sourcin... проект RacerD (http://fbinfer.com/docs/racerd.html), в рамках которого открыты наработки по выявлению проблем, возникающих из-за одновременного выполнения кода в многопоточных программах на языке Java. RacerD интегрирован в систему статического анализа Infer (https://github.com/facebook/infer) и обеспечивает определение потенциальных ошибок в коде, использующем классы/методы, заявленные как @ThreadSafe, или осуществляющем блокировки при помощи ключевого слова "synchronized".
RacerD сконцентирован на выявлении состояний гонки (https://ru.wikipedia.org/wiki/%D0%A1%D0%... возникающих между вызовом методов класса в разных потоках. Например, определяются ситуации, когда выполняется два одновременных обращения к переменной члена класса, не отделённой при помощи мьютекса, если в одном из обращений выполняется операция записи.
RacerD уже около 10 месяцев используется в Facebook и за это время помог выявить более тысячи проблем в многопоточном коде проектов для платформы Android, на стадии их разработки. Большая часть ошибок была выявлена в процессе перевода реализации ленты новостей в Android-приложении Facebook на многопоточную модель работы.
URL: https://code.facebook.com/posts/293371094514305/open-sourcin...
Новость: http://www.opennet.me/opennews/art.shtml?num=47426
Эх, вот где-то здесь и жалеешь, что для плюсов такое сделать проблематично
Один из симптомов шубообразной охватывающей шизофрении - страхи, и сильные сожаления без малейшей на то причины. (С) Твой доктор :-).... впрочем, если нет денег на PVS-studio и иже с ними (а их - легион!) - а _самому_ "сделать проблематично", то да - пост заиграитЪ совсем другими красками :)
Погугли "sanitizer" и больше не пиши тут чушь
нагугли мозг (ну или хотя бы чем отличаются sanitizer от static analize), и больше вообще не пиши.
В данном случае дело даже не в том - в джаве есть каноничный способ описать шареные объекты языком, понятным для инструментов - вышеупомянутые классы/методы, заявленные как @ThreadSafe, или осуществляющем блокировки при помощи ключевого слова "synchronized". В плюсах этого нет, поэтому анализ становится многократно сложнее. Понятно, что это цена богатства языка и наличия выбора, но всё равно завидно.
>В плюсах этого нет, поэтому анализ становится многократно сложнее.На самом деле нет. Разбор исходного кода настолько незначительная сторона статического анализа, что на ней можно не зацикливаться
речь не о самом разборе.В джаве "syncronized" полностью описывает всё поведение по локам - и указывает на наличие, мьютекса и то, что он лочится строго при входе в метод и раззлочивается строго при выходе. В плюсах - придётся ещё выяснять, где на самом деле происходит блокировка и как именно она используется. Впрочем, подумав, пожалуй, соглашусь с вами - в пределах джавовской простой модели синхронизации и при условии использования std::mutex и std::lock_guard особо сложнее быть не должно.
Какая доброта. И что же, интересно, не так? У вас какие-то проблемы?Thread Sanitizer - отличный инструмент, отлавливающий ошибки, которые иначе поймать было бы проблематично. В начале своей жизни умел мало, но теперь справляется со всем, что в него швыряют.
Только здесь речь вообще не о том.
Статик анализатор на это есть в clang с 2011 года:
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
https://llvm.org/devmtg/2011-11/Hutchins_ThreadSafety.pdfПроблема в том, что статик-анализ не работает в сложных случаях, поэтому на практике эти аннотации используются мало кем. Обычно используют динамический анализ (thread sanitizer):
http://www.cs.columbia.edu/~junfeng/11fa-e6121/papers/thread...
https://llvm.org/devmtg/2012-11/Serebryany_TSan-MSan.pdf
https://clang.llvm.org/docs/ThreadSanitizer.html
Какие-то местечковые аннотации на макросах? Действительно, и почему их никто не использует...
В C++03 макросы нужны, чтобы код компилировался на тех компиляторах, которые не поддерживают эти аттрибуты. Документация написана так, чтобы можно было использовать и в С++03 коде, поэтому она использует макросы.Если используется только C++11 и выше можно использовать C++11 аттрибуты без макросов. Компиляторы будут просто игнорировать неизвестные аттрибуты.
> Какие-то местечковые аннотации на макросах? Действительно, и почему их никто не использует...
Поверь мне это связано не с этим.
Насчёт макросов понял (хотя им с этого начинать надо бы - что вот так пишется на приличных плюсах, но для легаси тоже есть костыль), но есть и более серьёзные проблемы:
1) эти аннотации отделены от собственно кода синхронизации. То есть никто их соответствие реальному положению вещей не гарантирует.
2) необходимость заменять мьютекс своим типом.
3) необходимость вообще писать эти аннотации.А теперь сравните с джавой, где анализатор натравливается на стандартный, существующий код.
А если обобщить... Я не помню ни механизма аннотирования в помощь статическим анализаторам, который бы получил повсеместное распространение. Ну, то есть вообще. Даже Страуструп свой GSL пропихнуть не смог. Почему - можно гадать, но оно так.
> Насчёт макросов понял (хотя им с этого начинать надо бы - что вот так пишется на приличных плюсах, но для легаси тоже есть костыль), но есть и более серьёзные проблемыЯ согласен. Я думаю это связано с тем, что документация писалась в 2011 году, когда C++11 был менее распространен.
> 1) эти аннотации отделены от собственно кода синхронизации. То есть никто их соответствие реальному положению вещей не гарантирует.
Я не понял, что имеется ввиду. Анализ проверяет, что при обращении к переменной вызывающий код удерживает мьютексы, указанные в аттрибуте guarded_by у этой переменной. Что значит "никто их соответствие реальному положению вещей не гарантирует"? Анализ как раз проверяет, что взятие мьютексов согласованно с аттрибутами guarded_by.
Или ты имеешь ввиду, что аттрибуты guarded_by могут не соответствовать реальной логике работы программы? Ну здесь ничего не поможет. Компьютер не может знать какие данные защищены какими мьютексами.
Даже в RacerD есть guarded_by: http://fbinfer.com/docs/infer-bug-types.html#anonymous_inner
> 2) необходимость заменять мьютекс своим типом.
Почему ты так считаешь? В libc++ (реализация стандартной библиотеки идущая с clang) std::mutex аннотированы: https://github.com/llvm-mirror/libcxx/blob/276a69c18b3eeb6e8... Реализации стандарных библиотек других компиляторов не аннотированы аттрибутами, которые эти компиляторы не поддерживают, это предсказуемо.
> 3) необходимость вообще писать эти аннотации.
Тогда тебе будет не нравится статик-анализ вообще. Поскольку, как правило без дополнительных аннотаций он имеет либо много false-positive, либо много false-negative. А аннотации делают статик-анализ применимым на практике.
> выявить более тысячи проблемЭто всё, что вам надо знать о проектах для платформы Android.
> Это всё, что вам надо знать о проектахот Facebook
Не надо такое знать. Не надо читать анонимов опеннета, которые целенаправленно выдирают фразы из контекста, придавая им новые оттенки смысла.
Оригинальная фраза гораздо веселее: "более тысячи проблем [...] на стадии их разработки". Надо полагать, что, всё же, это оговорка (пускай и чисто по Фрейду), что подразумевалась разработка не проблем, а софта, проблемы же возникали в процессе разработки, и отлавливались статическим анализатором. И вот тут эта "тысяча проблем" превращается в маркетинговый буллшит, это всё равно что считать как много ошибок суммарно было выдано компилятором в процессе разработки программы, когда код перекомпилировался раз десять в день, и большая часть этих компиляций была нацелена на поиск опечаток или даже на диагностику текущего состояния программы, когда программист начал какое-то изменение, затрагивающее двадцать различных файлов, часть этих изменений внёс, и теперь ему надо вернуться назад и вспомнить, что именно он уже сделал, о чём лишь подумал, и о чём он не подумал, хотя стоило бы.
Думаю, тут смысл несколько другой. "На стадии разработки" - это дилетанское отражение фразы "на стадии проектирования". Вот ты сделал десяток классов, всё соединил, раскидал на трэды и тут решил проверить анализатором - и вот когда он находил проблемы, тогда и считалось "выявил". Другой вопрос, это всё равно чертовски много - неужели при всех этих "паттернах", которым зас***али весь мозг и тырнеты, фэйспук так и не научился применять шаблонные методы для типичных задач??
В любом случае, тот зоопарк языков, что там сейчас есть (https://www.quora.com/What-programming-languages-are-used-at... ) - это гетерогенная помойка, которой уже ничто не поможет.
> Думаю, тут смысл несколько другой. "На стадии разработки" - это дилетанское отражение
> фразы "на стадии проектирования".Почему ты выбираешь именно тот смысл фразы "на стадии разработки", который приписываешь дилетантам? Разработчики фейсбука могут быть кем угодно, но они не дилетанты, хотя бы уже потому, что они профессионалы, работающие за деньги и на полном рабочем дне.
> Вот ты сделал десяток классов, всё соединил,
> раскидал на трэды и тут решил проверить анализатором - и вот
> когда он находил проблемы, тогда и считалось "выявил".Я почитал оригинал, там чётко написано о том, что речь о 10 месяцах работы этого статистического анализатора с кодом в процессе разработки. Причём с кодом, который существовал и работал и до этого.
> Другой вопрос, это
> всё равно чертовски много - неужели при всех этих "паттернах", которым
> зас***али весь мозг и тырнеты, фэйспук так и не научился применять
> шаблонные методы для типичных задач??Основная претензия к корпоративному коду состоит в том, что он всегда использует шаблонные методы для шаблонных задач, всегда игнорирует реально существующий ТЗ и предполагает, что это ТЗ будет развиваться до тех пор, пока не станет полным описанием всей Вселенной. Из-за чего реализация hello world в корпоративном виде занимает полтысячи строк, которые ничего не делают. Эта извечная корпоративная попытка на этапе проектирования написать программу наиболее полно, так, чтобы её уже и не надо было писать никогда, как бы там не менялся ТЗ, мне кажется психическим заболеванием. Эдакой профдеформацией. Весь опыт показывает, что программы развиваются, что ТЗ меняются, и меняются они часто непредсказуемым образом. Ориентируясь на все варианты того, что может случиться через 20 лет, мы уже сегодня получаем монструозную архитектуру причём без каких-либо гарантий, что через 10 лет она всё же окажется непригодной для своих задач в их новой постановке, и её придётся переписывать с нуля.
Нет, конечно, бывает и другая крайность, когда в архитектуру программы на этапе проектирования закладывается так мало, что даже априорный ТЗ становится невозможным реализовать не подпирая его костылями.
Это всегда компромисс. И то, что фейсбук реализовал приложение "лента новостей" в однопоточном исполнении, мне кажется вполне нормальным. И я не поверю, что это не так, до тех пор пока не увижу из каких соображений исходили разработчики, когда исходно решали компромиссы проектирования.> В любом случае, тот зоопарк языков, что там сейчас есть (https://www.quora.com/What-programming-languages-are-used-at...
> ) - это гетерогенная помойка, которой уже ничто не поможет.Ей не нужна помощь. Они сами справляются. Пока по крайней мере. Вот когда они попросят помощи, вот тогда можно будет презрительно сказать, что здесь уже ничего не поможет, а пока этого нет, довольно странно намекать на то, что фейсбук уже весь разваливается, и вот-вот окончательно превратиться в руины.
> Это всегда компромисс. И то, что фейсбук реализовал приложение "лента новостей" в
> однопоточном исполнении, мне кажется вполне нормальным. И я не поверю, что
> это не так, до тех пор пока не увижу из каких
> соображений исходили разработчики, когда исходно решали компромиссы проектирования.В ваших рассуждениях есть одна типичная ошибка: вы предполагаете, что если в Яве что-то пишут без учёта многопоточности, то получается нечто однопоточное. Увы, это совершенно не верный посыл -- Ява ВСЕГДА МНОГОПОТОЧНАЯ. Чтобы приложение стало однопоточным его нужно специально писать ОДНОПОТОЧНЫМ, иначе оно будет НЕПРЕДСКАЗУЕМО МНОГОПОТОЧНЫМ.
Вот в чём дело.
Может быть, я с джавой знакомился лет пятнадцать назад, через полгода потерял к ней всякий интерес, и больше никогда не возвращался. Но, что-то мне подсказывает, что, всё же, вы сейчас каким-то образом пытаетесь натянуть сову на глобус. Ну, в том смысле, что мне ни разу не приходилось сталкиваться со сколь-нибудь грамотной критикой кода, которая базировалась на использовании капса и общих представлениях об использованных инструментах. Сколь-нибудь грамотная критика всегда содержит в себе хотя бы одну цитату из кода.
О каком коде вы говорите? Caps же -- это для тех, кто может только знакомится с Явой. Им важно помнить, что они всегда пишут многопоточную программу. Вы выше предположили, что коль проект крупный и раскрученный, то только в силу этого факта он всегда пример самых актуальных компетенций. По моему опыту, это совсем не так. Программеру нужно заботиться о хорошем коде, а не об удачном маркетологе: удачного маркетолога удаётся встретить единицам, а остальным нужно писать нормальный код.
И что же нам нужно знать?
> ситуации, когда выполняется два одновременных обращения к переменной члена класса, не отделённой при помощи мьютекса, если в одном из обращений выполняется операция записиВ модели памяти это называется Data Race. И необязательно необходим мьютекс. Так вот, Data Race != Race Condition. Эти проблемы могут быть в наличии как одновременно, так и каждая по-отдельности.
> В модели памяти это называется Data Race. И необязательно необходим мьютекс.
> Так вот, Data Race != Race Condition.Хвать гнать, Race Condition - это общее описание всех багов возникающих при доступе к чему-либо, двух и более кого-либо.
Есть такие баги "Time of check to time of use (TOCTOU)", тож разновидность race condition.
не гуглятся примеры dr vs rc? я помогу https://blog.regehr.org/archives/490
> не гуглятся примеры dr vs rc? я помогу https://blog.regehr.org/archives/490Еще раз: "Race Condition - это общее описание всех багов возникающих при доступе к чему-либо, двух и более кого-либо."
У вас в примере классический race cond."multiple threads can concurrently try to update an account balance".
В решении корявое решение в стиле Winows (с надеждой на компилятор). Отбалды делать атомарные операции
над не атомарными перемененными ну совсем не гарантирует атомарность. Linux так вообще этого не позволит.
>> не гуглятся примеры dr vs rc? я помогу https://blog.regehr.org/archives/490
> Еще раз: "Race Condition - это общее описание всех багов возникающих
> при доступе к чему-либо, двух и более кого-либо."
> У вас в примере классический race cond."multiple threads can concurrently try to
> update an account balance".
> В решении корявое решение в стиле Winows (с надеждой на компилятор). Отбалды
> делать атомарные операции
> над не атомарными перемененными ну совсем не гарантирует атомарность. Linux так вообще
> этого не позволит.По-моему, вы немного не о том. Гонка возникает, когда есть... гонка. Т.е. непредсказуемая последовательность "приходящих к финишу" чего-то там. Вы же говорите о ложном суждении о естественной атомарности инвариантов. А атомарность инвариантов нужно описывать разрабу и описывать осмысленно. Компилятор этого не сделает.
В общем, и в литературе эту ситуацию почему-то запихивают в "гонку". Хотя тут никакой гонки нет.
Во-первых, в статье нет решений, есть только примеры, показывающие разницу между rc и dr.
Во-вторых, приведены они в псевдокоде. "Атомарная операция" определяется нестрого, это не конструкция языка, и атомарные переменные тут не при чем. Важно лишь, что результат в блоке одновременно видим или невидим всем потокам. Реализовать можно через системный мьютекс, Linux позволит, я гарантирую.
......Пля, модыр, трахни в моск свой кревой парсер
Это всё гонка. Т.е. когда состояние обобществлённого ресурса зависит от (псевдо)случайных факторов, а не прописано логикой алгоритма.
Race condition обязательно нарушает логику алгоритма (семантику, инварианты, или как хотите) при неблагопрятном стечении обстоятельств. Data race - совсем не обязательно.
Агх. Не уверен. Гонка возникает, чаще всего, из-за неверного суждения разраба о том, что вот как поток кода следует в его описании, так он и будет исполнятся. Более того, будет исполнятся "континуумно", т.е. без gaps-ов между строками выражений. Но проблема в том, что Ява, и не только она, в этом плане совершенно обманчива -- код на стадии исполнения перемешивается непредсказуемым образом (как оптимизатор решит), если только явно не предписать его прецеденцию. А уж многопоточность усложняет картину ещё больше.
DR же возникает из-за другого заблуждения -- что компилятор каким-то немыслимым образом определить желаемые границы атомарного инварианта просто просмотрев члены экземпляры (класса). Но это тоже невозможно. Т.е. DR это и не гонка совсем, по-моему.
> Race condition обязательно нарушает логику алгоритма (семантику, инварианты, или как хотите)
> при неблагопрятном стечении обстоятельств. Data race - совсем не обязательно.RC как раз ничего не нарушает -- нельзя нарушить то, что не предписано. Просто нужно зарубить себе на носу, что прецеденция исходного кода не будет сохранена на стадии исполнения. Если компилятору не сообщить как именно это сделать. Иначе -- будет как попало. Ява не сохраняет прецеденцию исходного кода (это так, для тех, кто не в курсе) по умолчанию.
> Это всё гонка. Т.е. когда состояние обобществлённого ресурса зависит от (псевдо)случайных
> факторов, а не прописано логикой алгоритма.... Итак, резюмирую. Гонка всегда результат неверного суждения об исполнительной среде. А не порок языка. По крайней мере, в Яве.
Никаких связей с растовым racer, ага.
Растоманам везде раст мерещится
есть ли неигровое приложение под андроид, более нагружающее мобилку, чем фейсбук? Я серьёзно. Сбербанк-онлайн не предлагать.
На мой не слишком проницательный взгляд история многопоточности в Яве это история про то, как сначала усиленно и целенаправленно делать дуршлаг, потому что дуршлаг все хотят, а потом сделав -- делать затычки для дырочек в этом друшлаге. Многопоточность в Яве "слишком гибкая", т.е. слишком много зависит от степени трезвости разработчика.
как раз по части модели памяти джава всегда была очень продвинутой. актуальную модель памяти плюсов делали в том числе опираясь на джавовую, но вот, к примеру, с OoTA-значениями так и не разобрались.
> как раз по части модели памяти джава всегда была очень продвинутой. актуальную
> модель памяти плюсов делали в том числе опираясь на джавовую, но
> вот, к примеру, с OoTA-значениями так и не разобрались.Местами даже через чур. Особенно в отсутствии внятной документации.
чересчур
Да
P.S: Хотя, не совсем. "Через чур" тоже можно употреблять -- это, как раз, исконное выражение. Одно из значений "Чур" -- граница. Т.е. "через чур" это через границу. Или сверх меры. Так что, всё Ок.