4遇到的问题

1、  如何解决printf导致两个线程频繁切换?

这个问题的解决方法在前面已经明确了,就是分配一个很大的输出缓冲区,在写到一定程度时再一次性用printf输出,避免printf的频繁调用。最好实在程序结束时输出统计和信息。

 

2、  在使用锁之后,是否会导致线程的频繁切换?

这也是我的疑问,后来在windows上做了一个实验证明了不同的锁会引起不同的线程调度行为。

DWORD WINAPI ThreadProc(LPVOID)

{

    char buf[1000];

    LARGE_INTEGER li;

    for (int i = 0; i < 100; ++i)

    {

        LOCK();  //这是个宏,用于切换使用各种锁

        test();

        QueryPerformanceCounter(&li);

        sprintf(buf, "thread id = %lu, getlock at %lu\n",

            GetCurrentThreadId(), li);

        StringOut(buf); //巨大的内存缓冲

        UNLOCK();

    }

    return 0;

}

 

 

DWORD WINAPI ThreadProc(LPVOID)

{

    char buf[1000];

    LARGE_INTEGER li;

    for (int i = 0; i < 100; ++i)

    {

        LOCK();  //这是个宏,用于切换使用各种锁

        test();

        QueryPerformanceCounter(&li);

        sprintf(buf, "thread id = %lu, getlock at %lu\n",

            GetCurrentThreadId(), li);

        StringOut(buf); //巨大的内存缓冲

        UNLOCK();

    }

    return 0;

}

 

这个线程处理函数被两个不同的线程调用,并在输出中打印被调用的时间,在使用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、  为什么在DEBUG版本中,双队列和共享队列的性能一样?甚至还比共享队列方式慢?

不得不承认我在这里犯了一个非常愚蠢的错误,由于双队列编码的复杂性我在双队列中使用了大量的assert来保证bug能够快速被发现和修正,每个数据的处理流程中都比共享队列方案中多使用4assert,在测量1GINT数据的吞吐量时,assert语句耗时惊人。所以导致一个现象是,在DEBUG版本中双队列和共享队列方案的性能一样,而在RELEASE版本中(没有assert)双队列是共享队列方案性能的10多倍。

非常感谢我的计算机老师何笑帮助我发现这个问题,他总是在我最困惑的情况下给于帮助,下面这个程序可以证明在一定数据量后assert的调用导致大量CPU开销。

DWORD WINAPI ThreadProcUseAssert(LPVOID)

{

    //N很大时,assert的开销会非常明显

    for (int i = 0; i < N; ++i)

    {

        __asm {  //阻止编译器优化掉循环

             Nop

        }

       assert(1);

       assert(2);

       assert(3);

       assert(4);

    }

    return 0;

}

 

 

 

DWORD WINAPI ThreadProcUseAssert(LPVOID)

{

    //N很大时,assert的开销会非常明显

    for (int i = 0; i < N; ++i)

    {

        __asm {  //阻止编译器优化掉循环

             Nop

        }

       assert(1);

       assert(2);

       assert(3);

       assert(4);

    }

    return 0;

}

 

4、  在公司调试双队列程序时,为什么出现频繁的内存非法访问?而又找不出代码的问题?

对于这个问题,我极端的无语!那是因为我使用了办公机中VC6下已有的一个Project文件,此文件中针对Application的配置是Single-Thread,起初一直认为是自己编写的代码有问题,定位了大概3个小时,最后发现不同线程malloc两次分配了同一个地址,这时才恍然大悟是链接了单线程版本的库函数。解决方法是在VC6菜单中的 Project->Setting将其改为Multi-Thread后想象消失。

posted on 2011-05-10 21:14  30斤大番薯  阅读(613)  评论(0编辑  收藏  举报