4遇到的问题
1、
这个问题的解决方法在前面已经明确了,就是分配一个很大的输出缓冲区,在写到一定程度时再一次性用printf输出,避免printf的频繁调用。最好实在程序结束时输出统计和信息。
2、
这也是我的疑问,后来在windows上做了一个实验证明了不同的锁会引起不同的线程调度行为。
DWORD WINAPI ThreadProc(LPVOID)
{
}
DWORD WINAPI ThreadProc(LPVOID) { } |
这个线程处理函数被两个不同的线程调用,并在输出中打印被调用的时间,在使用Critical Section时打印内容如下:
thread id = 2200, getlock at 882789456
thread id = 2200, getlock at 882790147
thread id = 2200, getlock at 882790233
<... REPEAT 96 times ...>
thread id = 2200, getlock at 882798374
thread id = 784, getlock at 882798487
thread id = 784, getlock at 882798604
thread id = 784, getlock at 882798693
<... REPEAT 96 times ...>
thread id = 784, getlock at 882805814
thread id = 2200, getlock at 882789456 thread id = 2200, getlock at 882790147 thread id = 2200, getlock at 882790233 <... REPEAT 96 times ...> thread id = 2200, getlock at 882798374 thread id = 784, getlock at 882798487 thread id = 784, getlock at 882798604 thread id = 784, getlock at 882798693 <... REPEAT 96 times ...> thread id = 784, getlock at 882805814 请按任意键继续. . . |
对于Critical Section来说并不是每次上锁和解锁都会产生线程切换。
对于Mutex 则有以下输出:
thread id = 2360, getlock at 771657703
<... REPEAT 15 times ...>
thread id = 2360, getlock at 771660102
thread id = 3316, getlock at 771660261
thread id = 2360, getlock at 771660482
thread id = 3316, getlock at 771660671
thread id = 2360, getlock at 771660955
thread id = 3316, getlock at 771661121
<... some result ignored ...>
thread id = 3316, getlock at 771702420
thread id = 2360, getlock at 771702694
thread id = 2360, getlock at 771920375
请按任意键继续. . .
thread id = 2360, getlock at 771657703 <... REPEAT 15 times ...> thread id = 2360, getlock at 771660102 thread id = 3316, getlock at 771660261 thread id = 2360, getlock at 771660482 thread id = 3316, getlock at 771660671 thread id = 2360, getlock at 771660955 thread id = 3316, getlock at 771661121 <... some result ignored ...> thread id = 3316, getlock at 771702420 thread id = 2360, getlock at 771702694 thread id = 2360, getlock at 771920375 请按任意键继续. . . |
这里可以看出使用Mutex锁之后,线程调度明显变得非常频繁,而且根本没有规律。这与WINDOWS的开发说明也是一样的,因为Critical Section不会在上锁和解锁时并不陷入内核,而Mutex则每次加锁和解锁都会陷入内核态,所以系统调用导致了更频繁的调度。
3、
不得不承认我在这里犯了一个非常愚蠢的错误,由于双队列编码的复杂性我在双队列中使用了大量的assert来保证bug能够快速被发现和修正,每个数据的处理流程中都比共享队列方案中多使用4个assert,在测量1G个INT数据的吞吐量时,assert语句耗时惊人。所以导致一个现象是,在DEBUG版本中双队列和共享队列方案的性能一样,而在RELEASE版本中(没有assert)双队列是共享队列方案性能的10多倍。
非常感谢我的计算机老师何笑帮助我发现这个问题,他总是在我最困惑的情况下给于帮助,下面这个程序可以证明在一定数据量后assert的调用导致大量CPU开销。
DWORD WINAPI ThreadProcUseAssert(LPVOID)
{
}
DWORD WINAPI ThreadProcUseAssert(LPVOID) { } |
4、
对于这个问题,我极端的无语!那是因为我使用了办公机中VC6下已有的一个Project文件,此文件中针对Application的配置是Single-Thread,起初一直认为是自己编写的代码有问题,定位了大概3个小时,最后发现不同线程malloc两次分配了同一个地址,这时才恍然大悟是链接了单线程版本的库函数。解决方法是在VC6菜单中的 Project->Setting将其改为Multi-Thread后想象消失。