天天看点

线程优先级差别的实际作用

今天无聊就想随便测试一下所谓线程优先级的高低到底对时间片分配有多大影响,测试代码如下:

DWORD CALLBACK thread_fun2 (LPVOID);

long i=0;

int cnt_1=0;

int cnt_2=0;

#define CNT 60000

DWORD CALLBACK thread_fun1 (LPVOID lpParam)

{

DWORD thread_id;

PHANDLE phThread2=(PHANDLE)lpParam;

SECURITY_ATTRIBUTES sa;

int i_bak=0;

sa.nLength=sizeof(SECURITY_ATTRIBUTES);

sa.bInheritHandle=TRUE;

sa.lpSecurityDescriptor=NULL;

*phThread2=CreateThread (&sa,0,thread_fun2,(LPVOID)NULL,CREATE_SUSPENDED,&thread_id);

SetThreadPriority (*phThread2,THREAD_PRIORITY_IDLE);

ResumeThread (*phThread2);

//Sleep (0);        //Sleep (1);

//for (int j=0;j<10000;j++)

// Sleep (0);

do

{

     i_bak=InterlockedExchangeAdd (&i,1);

     printf ("thread1:%d/n",i_bak);

     cnt_1++;

}while (i_bak<CNT);

printf ("thread1 ended!/n");

return 0;

}

DWORD CALLBACK thread_fun2 (LPVOID lpParam)

{

int i_bak=0;

//Sleep (0);

do

{

     i_bak=InterlockedExchangeAdd (&i,1);

     printf ("thread2:%d/n",i_bak);

     cnt_2++;

}while (i_bak<CNT);

printf ("thread2 ended!/n");

return 0;

}

int main ()

{

SECURITY_ATTRIBUTES sa;

sa.nLength=sizeof(SECURITY_ATTRIBUTES);

sa.bInheritHandle=TRUE;

sa.lpSecurityDescriptor=NULL;

DWORD thread_id;

HANDLE hThread2;

HANDLE hThread1=CreateThread (&sa,0,thread_fun1,(LPVOID)(&hThread2),CREATE_SUSPENDED,&thread_id);

SetThreadPriority (hThread1,THREAD_PRIORITY_BELOW_NORMAL);

ResumeThread (hThread1);

WaitForSingleObject (hThread1,INFINITE);

WaitForSingleObject (hThread2,INFINITE);

printf ("cnt_1:%d/tcnt_2:%d/n",cnt_1,cnt_2);      //线程1,2的执行次数

return 0;

}

        首先,用上面代码运行肯定会出现CPU占用100%,但具体是哪个进程占用CPU呢?我一开始以为会是进程本身,常理就是如此,但实际上是CSRSS进程占用92%左右的CPU.

        CSRSS是操作系统负责处理图形界面的进程.也就是说printf函数执行后程序等待CSRSS处理实际的输出工作,进程本身已经被阻塞了,等待处理结果.等CSRSS处理完成后再激活阻塞进程,CSRSS进程扮演了低速IO终端的角色,整个过程类似于中断,最忙碌的当然就会是CSRSS了.道理很简单,只是直觉认识错误罢了.

        其次,如果有printf语句,相同优先级线程1,2执行次数相差不多.但如果注释掉的话,如果线程1优先级不够高,在线程2执行完之前根本不会有机会得到执行.其中的互斥访问机制根本没有任何作用,因为线程2在线程1创建2后的一个时间片里已经执行完了所有循环.如果在2函数中加一句Sleep (0);也就是说放弃一次时间片,结果就反过来了.

         而且我发现假如1比2的优先级高一级,那么直接2就没机会执行了,如果在创建2后加一句Sleep (0);放弃一次时间片,仍是如此,但如果再加一句Sleep (0)就没机会了,也就是说高一级操作系统会多分配两个时间片.但假如高两级,那么即使for (int j=0;j<60000;j++)Sleep (0);这样也没办法让线程2争取到CPU,可见高两级时操作系统绝对会先处理高优先的线程,哪怕前者放弃了如此多次的时间片.但是如果用一句Sleep (1),那么高多少级都没用了,可见1毫秒的时间实在是太长了.

          以上都是在单核处理器上测试的,用双核的话肯定就不会如此了,有条件的可以在双核上试一试,纯粹娱乐吧.