Я следую этот урок чтобы понять, как снять блокировки, используя VTUNE
Эта страница говорит следующее после сбора результатов Vtune:
Определите самые горячие строки кода
Нажмите кнопку навигации горячей точки
перейти к строке кода, которая заняла больше всего времени ожидания. VTune Amplifier
выделяет строку 170, входящую в критическую секцию rgb_critical_section
в функции draw_task. Функция draw_task ждала
почти 27 секунд, пока выполнялась эта строка кода и большая часть
время процессор был использован недостаточно. За это время критическое
раздел был оспорен 438 раз.Раздел rgb_critical — это место, где находится приложение
сериализация. Каждый поток должен ждать критического раздела, чтобы быть
доступны, прежде чем он может продолжить. Только один поток может быть в
критический раздел за один раз. Вам нужно оптимизировать код, чтобы сделать его
более одновременно.
Я мог следовать этому уроку, пока не достиг следующего раздела: Снять замок
Снять замок
Rgb_critical_section был введен для защиты вычислений от
многопоточный доступ. Краткий анализ показывает, что код является потоком
безопасный и критический раздел на самом деле не нужен.
Мой вопрос: как мы узнаем, что код безопасен для потоков?
Как и предполагалось, я прокомментировал эти строки (EnterCritical … и LeaveCritical …) и увидел огромный прирост производительности, но я не понял, почему этот критический раздел не требуется? Какой анализ говорит нам об этом?
Соответствующий код находится здесь в analy_locks.cpp:
public:
void operator () (const tbb::blocked_range <int> &r) const {
unsigned int serial = 1;
unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
memset(local_mbox,0,mboxsize);
for (int y=r.begin(); y!=r.end(); ++y) {
drawing_area drawing(startx, totaly-y, stopx-startx, 1);
// Enter Critical Section to protect pixel calculation from multithreaded access (Needed?)
// EnterCriticalSection(&rgb_critical_section);
for (int x = startx; x < stopx; x++) {
color_t c = render_one_pixel (x, y, local_mbox, serial, startx, stopx, starty, stopy);
drawing.put_pixel(c);
}
// Exit from the critical section
// LeaveCriticalSection(&rgb_critical_section);
if(!video->next_frame()) tbb::task::self().cancel_group_execution();
}
}
draw_task () {}
};
Что-то является потокобезопасным, если глобальное состояние (то есть состояние вне этого конкретного потока) не изменяется. Нам сложно сказать, что render_one_pixel
а также drawing.put_pixel
на самом деле, и в каком порядке это может быть необходимо выполнить.
Предполагая, что порядок звонков put_pixel(c)
не имеет значения (или какой поток делает вызов), было бы безопасно удалить критический раздел здесь. Если требуется строгий порядок, я не уверен, что критический раздел в любом случае является правильным решением. (Те же правила, безусловно, применяются к render_one_pixel
, если оно меняет какое-то глобальное состояние, что, конечно, также должно быть учтено в «Безопасно ли это»).
Других решений пока нет …