我正在关注this tutorial以了解如何使用VTUNE来删除锁定 收集Vtune结果后,此页面显示以下内容:
识别最热门的代码行
单击热点导航按钮 转到花费最多等待时间的代码行。 VTune放大器 突出显示第170行进入关键部分rgb_critical_section 在draw_task函数中。 draw_task函数正在等待 这段代码行正在执行时大约27秒 处理器未充分利用的时间。在这段时间里,关键 该部分争论了438次。
rgb_critical部分是应用程序所在的位置 序列化。每个线程都必须等待临界区 在它可以继续之前可用。只有一个线程可以在 一次关键部分。您需要优化代码才能实现它 更多并发。
我能够按照本教程进行下一部分:Remove the Lock
取消锁定
引入了rgb_critical_section以保护计算 多线程访问。简要分析表明代码是线程 安全,并不是真正需要关键部分。
我的问题是我们如何知道代码是线程安全的?
正如所建议的那样,我评论了那些行(EnterCritical ...和LeaveCritical ......),并且看到了巨大的性能提升,但我不明白为什么不需要这个关键部分?哪个分析告诉我们这个?
相关代码在analyze_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 () {}
};
答案 0 :(得分:1)
如果没有修改全局状态(即,在此特定线程之外的状态),则某些事情是线程安全的。我们很难说出render_one_pixel
和drawing.put_pixel
实际上做了什么,以及它可能需要执行的顺序。
假设对put_pixel(c)
的调用顺序无关紧要(或哪个线程进行调用),可以安全地删除此处的关键部分。如果需要严格的订购,我不确定关键部分是否是正确的解决方案。 (同样的规则明显适用于render_one_pixel
,如果它改变某些全球状态,当然也必须在“它是安全的”中加以考虑。