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

    +24

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    void sleep_in_qt_ms(unsigned millisec) {
        QMutex foo;
        foo.lock();
        foo.try_lock(millisec);
        foo.unlock();
    }

    sleep в Qt - что, серьезно, чтоли?

    особенно порадовало: Warning: Destroying a locked mutex may result in undefined behavior.
    действительно, накой нам деструкторы?

    Запостил: defecate-plusplus, 29 Марта 2013

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

    • Там есть QThread::sleep()/usleep()/msleep(), запрятанные в protected'ы, чтобы с главного треда не очень хотелось вызывать их. Ибо sleep в GUI потоке нахер не сдался.

      > Warning: Destroying a locked mutex may result in undefined behavior.
      Ну дык мутекс мог залочить один поток, а второй вызовет у него деструктор... Вот видимо такие случаи и имелись в виду.
      Ответить
      • как это можно сделать?
        только передать во второй поток этот мутекс по ссылке и указателю (надеюсь, что QMutex - noncopyable, верно?)
        раз так, то это плохо вообще для чего угодно, даже для инта, дереференситься к удаленному объекту
        Ответить
        • > только передать во второй поток этот мутекс по ссылке и указателю
          Хм. Ну а нахрена, простите, сдался мутекс, если его не юзают как минимум 2 потока?
          Ответить
          • кроме передачи по ссылке или указателю существуют другие способы, позволяющие двум потокам иметь доступ к одному мьютексу - и эти способы принципиально не будут иметь проблемы "поток хозяин удалил мютекс, которым я пользуюсь"
            например, потоки работают по методам одного и того же объекта, и понятное дело, они оба имеют доступ к мьютексу - члену этого объекта - и тут оба потока обязаны умереть раньше, чем вызовется деструктор мьютекса
            Ответить
            • > и эти способы принципиально не будут иметь проблемы
              Да тут будет та же самая проблема, если какой-то из потоков надумает выпилить этот объект (да, естественно, так никто делать не будет, как собственно и разрушать мутекс не сняв с него локи).

              > оба потока обязаны умереть раньше, чем вызовется деструктор мьютекса
              Воот... Правильная мысль. Юзеры объекта должны перестать пользоваться мутексом до вызова его деструктора. А если они перестали им пользоваться - они мало того, что его анлокнули, так еще и должны воздержаться от последующих вызовов lock(). Следовательно проблема с undefined behavior надуманная, и возникает только в кривых случаях, которые сами по себе undefined behavior.
              Ответить
              • ну а написано в хелпе именно так, что я обязан в 5 строчке сделать unlock вручную
                Ответить
                • Не хочешь вызывать lock()/unlock() вручную - юзай QMutexLocker.

                  Вызвал lock() вручную - будь добр вызвать unlock() в том же треде тоже вручную.

                  P.S. Прога с непарными lock()/unlock() она ведь сама по себе уже бажная...
                  Ответить
                  • да ну их нахер, я уже давно запилил с nanosleep, просто результаты гугленья на тему qsleep привели меня в ужас

                    всё равно в будущем, если придется писать нормально, то придется писать с нуля, а не пользоваться qt-шным примером
                    постигла меня эта кара к концу недели, измазался уже по самое немогу
                    Ответить
      • > Ибо sleep в GUI потоке нахер не сдался.
        вот мне прямо сейчас сдался, например, а компилить буст для демки тестовой платформы мне пока что очень западло

        > QThread::sleep()/usleep()/msleep()
        превосходная идея с клонированием сотни одинаковых функций, вместо того, чтобы сделать нормальный класс, хранящий duration (QMilliseqonds, да) и передавать его один в одну функцию Qsleeq
        впрочем, я не удивлен
        Ответить
        • Костылик:
          struct Sleepy : public QThread {
              static void sleep(int ms) {
                  QThread::sleep(ms);
              }
          };
          
          Sleepy::sleep(1000);
          Ответить
        • >>вместо того, чтобы сделать нормальный класс, хранящий duration (QMilliseqonds, да) и передавать его один в одну функцию Qsleeq

          У вас сарказм отвалился. Вы же это не серьезно, да?
          Ответить
          • Вполне серьезно. Единый тип для duration'ов и наглядные конструкторы рулят:
            // это - 30 секундный таймаут, понятный даже непосвященному
            const boost::posix_time::time_duration session_timeout = boost::posix_time::seconds(30);
            
            // А в чем же измеряется хуйня строчкой ниже?
            // И вообще время ли это, или просто код ошибки,
            // который возвращается при таймауте сессии...
            const unsigned int session_timeout = 30;
            Ответить
            • > Единый тип для duration'ов и наглядные конструкторы рулят:

              много писанины. я пару софтин перевел на double для хранения таймаутов и прочего. 30 - 30 секунд, 0.5 - 500мс, 0.0001 - 100юс, и т.д.
              Ответить
      • вот только небольшой фейл: кутешники рекомендуют юзать стандартный QThread, т.к. это интерфейс управления потоком, а логику делать в своем классе, который отправлять в новый поток
        Ответить
        • Это не только кутешники советуют, это всеобщая практика, boost::thread вон шаблонный function object принимает в конструкторе. И в жабе наследоваться от Thread - моветон.
          Ответить
          • Под фейлом он имел в виду protected sleep.
            Ответить
            • Это я понял :)
              protected sleep подразумевает, что нужно наследоваться, а наследование тут нафиг не нужно. Логично как в PHP
              Ответить
              • Ну я так понял, что это защита от дурака. Кому очень-очень надо - сумеет добраться. Остальным sleep в event-driven системе не нужен.

                Что-то типа NetworkInMainThreadException в андроиде.
                Ответить
    • QMutex не может в повторный рекурсивный вход - что, серьезно, чтоли? Даже сишарпик это осилил.
      Ответить
    • Тем временем в Qt5 sleep сделали пабликом: http://qt-project.org/doc/qt-5.0/qtcore/qthread.html#sleep.
      Ответить
    • Чем std::mutex не подошёл?
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • Если вызвать в двух тредах, то второй будет ждать, пока первый поспит?
      Ответить
      • Почему? У каждого свой мутекс.
        Ответить
        • Разве смысл мутекса не в том, чтобы в блок зашёл только один тред, а другой ждал?
          Ответить
          • Так это если мьютекс общий для нескольких тредов. А автор обсуждаемого кода абьюзит мьютексы таким вот нестандартным образом.
            Ответить
            • В смысле общий? Есть мьютексы, которые шарятся между тредами, а есть которые нет? Это не каждый петух знает.
              Ответить
              • ну ты код почитай
                тред работает, создает мутекс для себя, лочит его и его же и ждёт заданное число времени
                никакой другой тред не в курсе про этот мутекс
                Ответить
                • А, понял. Чтобы другие треды знали, нужно сделать его глобальным. Затупил.
                  Ответить
                • это такой способ сделать слип?
                  Ответить

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