1. C++ / Говнокод #17505

    +54

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    // We now have a locale string, but the global locale can be changed by
    // another thread. If we allow this thread's locale to be updated before we're done
    // with this string, it might be freed from under us.
    // Call versions of the wide-to-MB-char conversions that do not update the current thread's
    // locale.
    
    //...
    
    /*
                 * Note that we are using a risky trick here.  We are adding this
                 * locale to an existing threadlocinfo struct, and thus starting
                 * the locale's refcount with the same value as the whole struct.
                 * That means all code which modifies both threadlocinfo::refcount
                 * and threadlocinfo::lc_category[]::refcount in structs that are
                 * potentially shared across threads must make those modifications
                 * under _SETLOCALE_LOCK.  Otherwise, there's a race condition
                 * for some other thread modifying threadlocinfo::refcount after
                 * we load it but before we store it to refcount.
                 */

    MS VS 2013 CRT

    Запостил: LispGovno, 23 Января 2015

    Комментарии (50) RSS

    • Ня!
      Ответить
      • KAWAI
        Ответить
        • Так и хотелось ответить что-нибудь в рифму, типа SASAI
          Ответить
          • , LALKA
            Ответить
            • Кто о чем, а гест о больном

              Ты лучше прочитай что написано в нульпосте и наматывай на ус. Это из кода setlocale
              Ответить
      • Съешь еще этих мягких японских няшек да запей онгоингами.
        Ответить
        • Няшки не нужны. Только сёнены! Фансервис для малолетних уёбков
          Ответить
          • Превозмогания не нужны. Только няшки делающие няшные вещи! Сенёны для малолетних уёбков.
            Ответить
            • Пей пивко, валяйся в кровати, смотри сёнены, где мужики показывают силу молодости и лупят друг друга
              Ответить
    • Вот до чего глобальные переменные доводят... Каждый раз делать реф/дереф - дорого, а не делать - опасно.
      Ответить
      • локали.

        на большинстве юнихов та же песня.

        на одном проекте реально из С вызывали жабу - только для того что бы Сшную локаль не трогать.
        Ответить
        • > на большинстве юнихов та же песня.
          Ну и таймзоны. Каким мудаком надо быть, чтобы сделать gmtime()+localtime(), но в обратную сторону замутить только один mktime() - х.з. Причем ни одна из этих функций не позволяет настраивать таймзону кроме как через окружение.

          P.S. В timegm() еще ман стёбный: предлагает не юзать его, а заменить на говно с установкой TZ=UTC и вызовом mktime (можно смело выкладывать на ГК).
          Ответить
          • Я не смог пройти мимо: http://govnokod.ru/17507
            Ответить
          • Угу, и в С++ вряд ли добавят нормальные классы для работы с датами, так как же есть сишные либы, которые это делают (хоть и хреново).

            Я джвадцать лет жду возможности нормально завершить программу из любого места кроме как выбрасыванием исключения и ловли его в main()
            Ответить
            • А как ты себе представляешь нормальное завершение программы? Там все и так нормально
              Ответить
              • Ну скажем на н-ном уровне вложенности вызовов мне понадобилось завершить программу. Прямо сейчас. С корректной отработкой деструкторов, чисткой ресурсов и т.д.
                У std::exit есть очень серьёзный недостаток: она не раскручивает стек. В сишке всем похуй, так как деструкторов нет, а в крестах это проблема ибо RAII.
                Остальные способы быстро выйти чистят ещё меньше. Вот и приходится кидать какой-нибудь exit_exception или возвращать определённое значение, проверять его в вызывающей функции, возвращать... пока не доберёшся до мэйна
                Ответить
                • в многопоточке юзают cancellation_token
                  Ответить
                • "Ну скажем на н-ном уровне вложенности вызовов мне понадобилось завершить программу. Прямо сейчас."

                  Пости примеры сюда. Мы посмеемся. Потому что это 100% навярняка говно.

                  Это верный знак кривой логики программы - или кривых рук программиста.

                  ЗЫ Бросание и ловление в мэйне уникального исключения. Это то как этот хак делается в крестах.
                  Ответить
                  • Мэйн → инстанс платформы → обработчик событий → сцена главного меню → обработчик кнопки.

                    Кнопка — выход. Делать ничего руками не нужно, RAII приберёт. Да, сейчас бросается исключение (не унаследованное ни от чего, чтобы случайно не ловилось) и ловится в мэйне.
                    Почему не дать exit ожидаемого поведения, мне непонятно. Для немедленного завершения программы без уборки есть quick_exit, abort, etc
                    Ответить
                    • Кидаешь quit message → текущий обработчик мирно дорабатывает → цикл обработки событий останавливается → управление уходит из main'а → всё красиво завершилось. exit() в данном случае не нужен.
                      Ответить
                      • Да, неплохой вариант.
                        Ни особых преимуществ, кроме централизованной обработки, ни недостатков, кроме большего объёма кода.

                        Просто у меня бомбит, что существует 4 минимально отличающиеся функции для аварийного завершения работы и ни одной для нормального.
                        Ответить
                        • > Да, неплохой вариант.

                          Э??

                          Это же стандартный книжный способ?

                          > существует 4 минимально отличающиеся функции для аварийного завершения работы

                          четыре? это какие именно? в позиксе/ц стандарте я помню только три: exit(), _exit() и abort(). и они очень сильно друг от друга отличаются.
                          Ответить
                          • > Это же стандартный книжный способ?
                            Да вроде бы вообще все(?) event loop'ы так построены. Ну с поправкой на то, как это сообщение отправляется: где-то именно сообщением (например winapi), где-то вызовом метода stop() или quit() у лупа (например boost::asio, qt)
                            Ответить
                            • > boost::asio
                              там ещё есть мега-способ с объектом work, который мешает циклу выйти.
                              Ответить
                              • + для серверов можно еще сделать graceful shutdown убив слушающий сокет. run() сам выйдет, когда все клиенты отцепятся.
                                Ответить
                    • > Почему не дать exit ожидаемого поведения, мне непонятно.

                      Потому что это в общем случае не возможно.

                      Простейший примеры: exit() из глубин конструктора; exit() в одном потоке и развертка стеков в других потоках.

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

                      Если у тебя это проблемы, то пользуйся синглтонами + спец функция выхода которая все синглтоны удаляет перед сисколом выхода.
                      Ответить
                      • > exit() из глубин конструктора
                        А в чём проблема? Как аварийное завершение конструктора: объект не считается созданным (хоть это и не важно, т.к использовать его некому), память возвращается обратно.

                        >exit() в одном потоке и развертка стеков в других потоках.
                        В общем случае exit() в многопоточном приложении ЕМНИП вызывает UB и сейчас, если текущий поток завершается до того как завершатся дочерние потоки.

                        Проблем с инициализацией нет, как и нет их с выходом, если деструкторы отработают. Вариант с исключением работает нормально, вариант предложенный bormandом тоже бы работал прекрасно.

                        Просто, как я отписал выше, иметь несколько почти не отличающихся функций для аварийного выхода и ни одной для нормального.
                        Ответить
                        • > память возвращается обратно.

                          причем тут память? это та же дежурная проблема объекта созданного на половину.

                          освобождение памяти как раз при выходе никого не интересует: процес закончится, вся память разом освободится.

                          > если текущий поток завершается до того как завершатся дочерние потоки.

                          exit() может быть вызван и в дочернем потоке.

                          вообщем я твоей проблемы просто не уловил. как раз в С сложнее сделать корректный выход из программы. потому что его в ручную делать надо. в С++ есть все средства, но народы строят такие кластерфаки ООП что сами потом разгрести не могут. я по старой традиции никогда ничего важного в конструкторы/деструкторы не пихаю, потому что предпочитаю иметь более тонкий контроль жизненого цикла объектов. это уже не говоря про то что как правило стараюсь всегда делать стого иерархические агрегации. если надо - несколько иерархий, но опять же с четким разганичением ответственностей этих иерархий. в последней большой крестовой программе которую, я мог бы сделать 100% корректный выход в любой точке программы вызовом друх delete'ов на глобальные объекты + exit().
                          Ответить
                          • > причем тут память? это та же дежурная проблема объекта созданного на половину.

                            И решать её так же как и в случае с исключениями: автором класса которому следует предусмотреть что случится если написанный им exit выполнится.
                            Вообще механика работы исключений для «стандартного» выхода подошла бы.

                            > exit() может быть вызван и в дочернем потоке.
                            И завершение работы программы до того как завершатся все потоки всё ещё UB, так что новых способов выстрелить в ногу это не приносит.

                            > вообщем я твоей проблемы просто не уловил.
                            Проблемы как таковой нет. Есть досада на отсутствие синтаксического сахара в языке и необходимость в общем случае использовать не предназначенные для этого инструменты.

                            Вот в стандарте есть:
                            exit(), (который как мне сказали по стандарту вызывается посли завершения main и поэтому его поведение не может быть изменено) вызывающий atexit функции и разрушающий статичные объекты.
                            quick_exit(), вызывающий обработчики at_quick_exit(), a затем _Exit
                            _Exit, завершающий работу программы без уборки
                            abort() отличающийся от _Exit только тем, что кидает сигнал.
                            Ответить
                            • > необходимость в общем случае использовать не предназначенные для этого инструменты.

                              а. наконец таки добрались до оригинальной проблемы.

                              > abort() отличающийся от _Exit только тем, что кидает сигнал.

                              кидает а может и не кидает. и как бы совсем не exit()

                              цель abort() в том что бы приложение в корку повалить програмно. дебаг фича.

                              exit()/quick_exit()/_exit() тоже как бы понятно. это просто хуки в разные фазы завершения программы, exit() самый верхний уровень, quick_exit() где-то по середине, и _exit() это более или менее живой syscall который в приложение никогда не возвращается.

                              стандартные стримы флашатся и деструкторы статических объектов вызываются exit()ом. (и atexit() хуки.)

                              quick_exit() ввели что бы разделить выход из программы от вызова деструкторов статических объектов.

                              другими словами. в общем случае тебе _exit() и quick_exit() не нужны. и abort() только для отладки. и остается только один вызов: exit().
                              Ответить
                              • Вот, завершение состоит из следующих фаз:
                                (размотка стека и выход и мэйна)
                                exit(): вызов обработчиков atexit и разрушение статических объектов
                                _Exit(): завершение программы.

                                quick_exit вызываетобработчики at_quick_exit(), a затем _Exit. Стоит слегка особняком.

                                Нет возможности принудить к исполнению первую фазу: развернуть весь стек и вернуть какое-либо значение из основной функции: для основного потока: main, для остальных — функция треда.
                                Ответить
                                • exit() стэк не разворачивает!!! никто ни разу там стэк не разворачивает!

                                  единственное что стэк разворачивает - это в С++ бросание исключений. весь код для разворачивания генерится компилером/берется из компилерной ран-тайм либы и живет исключительно в самой программе, в юзерспэйсе.

                                  кернелу, который "завершает" приложение, стэк и все прочее что там лежит в памяти приложения просто по барабану.

                                  единственное что остается неупомянутым напрямую это либц. но и она как бы *С* библиотека и в С разварачивания стэка в принципе нету.
                                  Ответить
                                  • Это мой косяк в форматировании: забыл разрыв строки поставить, чтобы то что в скобках читалось отдельной стадией. (и забыл дописать "Нормального завершения")
                                    В скобках оно, потому что это забота программиста и не часть автоматического завершения.
                                    Ответить
            • > кроме как выбрасыванием исключения и ловли его в main
              А ведь в питоне так и делают...
              Ответить
              • в крестах если делаешь потоки типа fire and forget это не сработает
                Ответить
          • к локалям стандарт пытаются прикрутить - но вот таймзоны как были так и остаются черной дырой.

            с локалями и таймзонами есть еще одна неожиданная проблемка портабельности: имена локалей и таймзонов ни фига не стандартизированы. на проекте пару лет назад на это дело нарвались - Solaris vs Linux - трахались месяца три: в каком месте, какое название для какой локали/таймзоны задавать. главные грабли были что сложно придти и сказать кастомеру "плиз ребутни все 20 серваков - нам надо новые конфиги проверить."
            Ответить
            • boost::locale для переносимости, нэ?
              Ответить
              • В си?
                Ответить
                • а си причем тут? это код из крестокомпилятора
                  Ответить
              • и что? все примеры напичканы `locale::global(loc);`. те же яйца - но теперь в крестой обертке.

                да и проблем и именами это в принципе решить не может, если конечно буст с собой не таскает свои собственные файлы определения локалей (как это делает жаба).
                Ответить
                • Там от бекенда зависит. ICU, емнип, всё с собой таскает в виде гигантской либы. Остальные бекенды операционку юзают, поэтому не особо переносимы (но имена локалей всё равно пишутся в позиксовом стандарте, и то радость).
                  Ответить
                  • > ICU, емнип, всё с собой таскает в виде гигантской либы.

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

      А ведь кроме сетлокали нужно видимо ещё что-то вызвать, чтобы полностью контекст тредлокальной питушни сбросить?
      Ответить
      • Это в MSVC или libc надо локали подкручивать в каждом потоке?
        Ответить
        • мсвц 2013 помоему
          Ответить
          • меня подобное и в glibc не удивит. с ходу не вспомню, в паре мест народ начал прикручивать TLS к глобальным переменным.
            Ответить
    • Вы хоть переведите что здесь происходит для незнающих английский? Мне кажется никто не понимает что запостил топикстартер, но все плюсуют., чтобы не показаться невеждами Типичная история про "новое платье короля". А король то голый!
      Ответить
      • Включи в кабинке accessibility.
        Ответить
      • У тебя точка после слова "невеждами" убежала в после слова "плюсуют"
        Ответить

    Добавить комментарий