Кресты / Говнокод #10937 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
static QPainterPath::ElementType qpaintengineex_line_types_16[] = {
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
    ... еще 12 строк ...
    QPainterPath::MoveToElement, QPainterPath::LineToElement
};

static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = {
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 1
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 2
    ... еще 29 строк ...
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 31
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 32
};

Qt 4.x.x, src/gui/painting/qpaintengineex.cpp
Как я понял, используется для ускорения функций drawLines и clip (дабы не выделять память и не заполнять path каждый раз).

Запостил: bormand bormand, (Updated )

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

  • вот из-за подобного код становится потоко-небезопасным.
    а заведомо в 1 потоке вполне оправдано.
    Ответить
    • > вот из-за подобного код становится потоко-небезопасным.
      Схуя? (Простите, других слов для ответа не нашлось).
      Ответить
      • Может быть, но только не в данном случае, а тогда, когда данные могут меняться.
        Ответить
        • У каждого паттерна или приема есть свои условия применимости. Ведь даже молоток может быть опасным, если им бить по голове 😉
          Ответить
      • поля статические, если будет заполнение из разных потоков...
        хотя, работа с гуи из нескольких потоков сама по себе тот еще ГК.
        Ответить
        • > если будет заполнение из разных потоков...
          Ну, в данном случае, их используют только для чтения...
          > хотя, работа с гуи из нескольких потоков сама по себе тот еще ГК
          В Qt оно и не работает. Максимум можно порисовать на QImage из соседнего потока.
          Ответить
          • наверное, я слишком много работаю с кодом, где нужно следить за потоко-безопасностью.
            вот и рефлекс уже выработался %( условный.
            Ответить
            • Threads are evil 😉

              Хотя если выработать для себя список правил по написанию безопасного кода, то не все так и ужасно.

              P.S. Не особо люблю потоки, мне больше нравятся процессы или асинхронная обработка, хотя, зачастую, выбора нет.
              Ответить
                • friend WINAPI DWORD ThreadProc( LPVOID pParam );

                  Проблема может быть с многопоточностью, если статические переменные локальные. Но и то, для POD - маловероятно.
                  Ответить
                • Треды - друзья человека ровно до тех пор, пока мы не выйдем за пределы уютной модели, в которой расшаренные данные полностью или по частям защищены mutex'ами, r/w-lock'ами и семафорами.

                  За пределами этой модели треды выпускают свои клыки, и пытаются откусить программисту ногу.

                  P.S. Я не утверждаю, что опытный программист не справится с тредами, и что они абсолютное зло. Я бы, скорее, назвал их злом необходимым.
                  Ответить
                  • Написание быстрого потокобезопасного кода, даже имея блокирующие очереди, mutex'ы, countDownLatch'и, etc. - сродни чёрной магии. Требуются годы опыта и детальное знание железа и модели памяти. В этом смысле да, потоки - зло.
                    Ответить
                    • > Написание быстрого потокобезопасного кода
                      Тут ключевое слово "быстрого". Для типичного потокобезопасного кода особого опыта не нужно. Справится любой программист, который выучил простые правила.

                      А вот быстрый код, выходящий за рамки мутексов, очередей и семафоров, это точно черная магия, за которую без опыта лучше не браться.
                      Ответить
                      • Да, я использовал слово "быстрого" сознательно.
                        Если синкать всё подряд, от потоков будет больше вреда, чем пользы - слишком много времени будет уходить на переключение контекста. В той же Java есть неплохие стредства для работы, но если начать разбираться, как эти средства реализованы, мозг закипит довольно быстро. Да и в этих средствах, написанных настоящими профессионалами, порой находят ошибки.
                        Ответить
                        • Если начать разбираться в деталях реализации, то мозг закипает даже от обычного мьютекса, куда уж там lock-free структуры 😉
                          Ответить
                  • если модель не рассчитана на многопоточность, тому должны быть веские причины
                    на дворе 2012 год, программист обязан хорошо подумать над тем, как он собирается использовать 4-6-8 ядер на пользовательской машине
                    и не столько уж это доставляет проблем, всего то надо выбрать удобный фреймворк
                    Ответить
                    • Не всем программам нужна многопоточность - "несколько потоков, исполняемых в общем адресном пространстве". Многим задачам больше подходит многопроцессная модель.
                      Ответить
                      • таких задач единицы
                        в 99% случаев потоков хватает
                        не хочется общего адресного пространства - не пользуйся общими переменными, раз так беспокоит "черная магия" написать одну строчку boost::mutex::scoped_lock lk(mymutex_); внутри блока {} / функции
                        да и thread local сносно работает

                        когда пишешь приложение, работающее одновременно с n сетевыми подключениями, m фоновыми задачами, то выполнять все их в основном потоке (даже с помощью iocp/waitformultipleobjects) - только создавать лишние лаги для основного потока, взаимодействующего с консолью
                        никто не говорит о параллельном расчете обратной матрицы на 200 потоках, обыденная повседневная многопоточность не требует сверхусилий, и даже наоборот, серьезно облегчает решение проблем с отзывчивостью - есть побочные потоки, они что то вошкаются со своими задачами, когда у них готов реальный результат, они об этом просто сообщают основному потоку, который принимает решение где и когда с этим результатом работать

                        удобство и масштабируемость такого решение в т.ч. ложится на плечи фреймворка, и если это всё делать руками, то конечно лениво и "многопоточность - зло"

                        просто прошли годы, а ватсон без трубки я без asio уже не могу
                        Ответить
                        • > "черная магия" написать одну строчку
                          Простая задачка: есть направленный граф задач, вершины - задачи (пусть будет экземпляр runnable), рёбра - зависимости между задачами. Нужно выполнить весь граф с учётом зависимостей (т.е. запуск задачи невозможен, пока задачи-зависимости не выполнены), по максимуму используя возможность параллелезации.
                          Даже в такой несложной задаче одной строчкой "чёрной магии" не обойтись.
                          Ответить
                          • такую задачу можно решить математически - написав приличный алгоритм обхода этого графа, в чем я не специалист ни разу, и в лоб -
                            есть K задач (вершин), M потоков, ограничений на К и М не накладывается,
                            состояние всех задач хранится в общем массиве, к которому ко всему прочему прилагается нечто, способное сигнализировать о моменте, что состояние массива изменилось (это может быть сделано с помощью condition variable, либо с помощью коллбека как я покажу ниже)
                            каждая задача знает набор, от которого она зависит, и по каждой реакции на вышеописанное событие ей следует посмотреть в этот массив, способна ли она начать свою работу. если не способна - делает return из коллбека

                            если делать конкретно на asio, то должен быть некий master object, в котором собственно и будет храниться массив выполненности задач, и который будет самостоятельно ждать события и самостоятельно же запускать задачи на выполнение обычным myioservice_.post(...thistask...).
                            событие о том, что задача закончилась - состояние массива требуется изменить - просто задача последнием действием делает коллбек в мастер обжект
                            с таким решением количество потоков задается в параметрах командной строки и хорошо работает как на 1 потоке, так и на 100

                            так что фактически с помощью asio не придется писать вообще ни одного мутекса
                            Ответить
                            • и главное, это всё сразу будет кроссплатформенно и совершенно бесплатно
                              покупайте нашу поебень
                              Ответить
                            • > не придется писать вообще ни одного мутекса
                              я не уверен, но вроде бы коллбэк может быть вызван сразу из нескольких потоков, и весьма вероятно будет нужна блокировка. Если только коллбэк - это не функтор, помещаемый в очередь сообщений для "master object" и выполняемый синхронно.
                              Ответить
                              • > Если только коллбэк - это не функтор, помещаемый в очередь сообщений
                                Имхо достаточно просто очереди сообщений с идентификатором задачи и ее результатом.
                                Ответить
                              • именно второе
                                чудес ведь не бывает, т.е. внутри асио конечно будут и мутексы, да и синхронизацию мастеробжекта (прием коллбека) надо бы сделать через strand - обёртка в асио, заставляющая все коллбеки внутри него исполняться строго неконкурентно
                                просто все вопросы балансировки по M потокам перекладываются на плечи фреймворка, что гуд
                                необходимо понимать, что все операции, связанные с помещением i-го коллбека в очередь j-го потока, не очень бесплатные, и потому оверхед стоит оценить по отношению к времени, которое требуется для каждой задачи (т.е. если они микросекундные, то в один поток последовательно получится быстрее, если они секундные и больше, то вполне имеет смысл параллелиться, конечно)
                                Ответить
                          • Берем мультимап, в котором будут храниться ссылки на невыполненные задачи, а ключом будет id первой задачи, от которой она зависит. Защищаем мап мутексом. Дальше нам понадобится блокирующая очередь, в которую сложим ссылки на задачи, которые ни от чего не зависят.

                            Запускаем пачку рабочих тредов.

                            Worker thread забирает задачу из очереди (fix: и выполняет ее), затем он захватывает мутекс на мап, и вынимает из мапа все задачи, в которых зависимостью была текущая. Задачи, у которых больше нет зависимостей уходят в очередь, у которых есть - обратно в мап с ключем следующей зависимости. После этого освобождается мутекс и тред снова забирает задачу из очереди.

                            Как насчет такого решения?
                            Ответить
                            • На первый взгляд должно работать. Попробую проверить на досуге реализацию на богомерзкой жабе. Сам решал способом, похожим на тот, что был предложен @defecate-plusplus (цепочка ListenableFuture<ExecutionStatus>).
                              Ответить
                    • > использовать 4-6-8 ядер
                      Характерно, что о многопоточности массы задумались только с появлением соотв. аппаратных возможностей на лоу-энд писюках.

                      http://hashcode.ru/questions/114371
                      Ответить
              • Модель clojure, к примеру, выглядит очень прилично: множество потоков, работающих с STM. Память общая, но запись в неё защищена системой транзакций. Довольно удобно, особенно по сравнению с ручными блокировками.
                Хотя сейчас в моду больше входит модель акторов с асинхронной передачей сообщений.
                Ответить
                • STM очень хорошая модель, но к сожалению пока медленная.
                  Ответить
              • а правил немного:
                1. стараться не юзать глобальные и статик-переменные
                2. если уж так нужно, то обращения только в критических секциях
                3. иные потоко-небезопасные вещи тоже.
                Ответить
                • Это только если нужны очень тривиальные вещи. Когда нужно что-то серьёзное, правил не существует.
                  Ответить
                • 1. По возможности минимизировать расшаренное состояние
                  2. Защитить все что осталось критическими секциями\мутексами\рвлоками.
                  ...
                  4. Профит

                  Но, к сожалению для скоростного приложения Роман прав. Правил нет. Только треш угар и содомия 😉
                  Ответить
  • интересно, qpaintengineex_rect4... почему rect, если
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement
    не обязательно является rect'ом?
    Ответить
    • Ну, видимо, потому что они всегда используют его для прямоугольников. Это же внутренний массив, часть реализации. А используется он вот в таком коде (форматирование немного примял, чтобы занимало меньше места):
      if (rects.size() <= 32) {
          qreal pts[2*32*4];
          int pos = 0;
          for (QVector<QRect>::const_iterator i = rects.constBegin(); i != rects.constEnd(); ++i) {
              qreal x1 = i->x();
              qreal y1 = i->y();
              qreal x2 = i->x() + i->width();
              qreal y2 = i->y() + i->height();
              pts[pos++] = x1; pts[pos++] = y1;
              pts[pos++] = x2; pts[pos++] = y1;
              pts[pos++] = x2; pts[pos++] = y2;
              pts[pos++] = x1; pts[pos++] = y2;
         }
          QVectorPath vp(pts, rects.size() * 4, qpaintengineex_rect4_types_32);
          clip(vp, op);
      } else {
          ... случай для больших регионов, в котором создается массив, и
          заполняется этими LineTo и MoveTo в цикле...
      }
      Ответить

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

Где здесь C++, guest?!

    А не использовать ли нам bbcode?


    8