VC创建的线程里面的程序何时运行,线程里的程序是否一直会一直运行,例如线程里的程序:getdi()。
答案:2 悬赏:40 手机版
解决时间 2021-02-28 17:48
- 提问者网友:夢醒日落
- 2021-02-28 08:00
getdi()能否反复运行
最佳答案
- 五星知识达人网友:七十二街
- 2021-02-28 08:27
当创建线程时或者唤醒已存在的线程时,线程函数体会执行,如果线程体内没有循环,也是一遍过的,跟主线程一样,在线程体内是顺序执行的。
全部回答
- 1楼网友:往事隔山水
- 2021-02-28 09:33
有许多应用程序创建的线程花费了大量时间在睡眠状态来等待事件的发生。还有一些线程进入睡眠状态后定期被唤醒以轮询工作方式来改变或者更新状态信息。线程池可以让你更有效地使用线程,它为你的应用程序提供一个由系统管理的工作者线程池。至少会有一个线程来监听放到线程池的所有等待操作,当等待操作完成后,线程池中将会有一个工作者线程来执行相应的回调函数。
你也可以把没有等待操作的工作项目放到线程池中,用queueuserworkitem函数来完成这个工作,把要执行的工作项目函数通过一个参数传递给线程池。工作项目被放到线程池中后,就不能再取消了。
timer-queuetimers和registeredwaitoperations也使用线程池来实现。他们的回调函数也放在线程池中。你也可以用bindiocompletioncallback函数来投递一个异步io操作,在io完成端口上,回调函数也是由线程池线程来执行。
当第一次调用queueuserworkitem函数或者bindiocompletioncallback函数的时候,线程池被自动创建,或者timer-queuetimers或者registeredwaitoperations放入回调函数的时候,线程池也可以被创建。线程池可以创建的线程数量不限,仅受限于可用的内存,每一个线程使用默认的初始堆栈大小,运行在默认的优先级上。
线程池中有两种类型的线程:io线程和非io线程。io线程等待在可告警状态,工作项目作为apc放到io线程中。如果你的工作项目需要线程执行在可警告状态,你应该将它放到io线程。
非io工作者线程等待在io完成端口上,使用非io线程比io线程效率更高,也就是说,只要有可能的话,尽量使用非io线程。io线程和非io线程在异步io操作没有完成之前都不会退出。然而,不要在非io线程中发出需要很长时间才能完成的异步io请求。
正确使用线程池的方法是,工作项目函数以及它将会调用到的所有函数都必须是线程池安全的。安全的函数不应该假设线程是一次性线程的或者是永久线程。一般来说,应该避免使用线程本地存储和发出需要永久线程的异步io调用,比如说regnotifychangekeyvalue函数。如果需要在永久线程中执行这样的函数的话,可以给queueuserworkitem传递一个选项wt_executeinpersistentthread。
注意,线程池不能兼容com的单线程套间(sta)模型。
为了更深入地讲解操作系统实现的线程池的优越性,我们首先尝试着自己实现一个简单的线程池模型。
代码如下:
typedefstruct_thread_pool
{
handlequitevent;
handleworkitemsemaphore;
longworkitemcount;
list_entryworkitemheader;
critical_sectionworkitemlock;
longthreadnum;
handle*threadsarray;
}thread_pool,*pthread_pool;
typedefvoid(*work_item_proc)(pvoidparam);
typedefstruct_work_item
{
list_entrylist;
work_item_procuserproc;
pvoiduserparam;
}work_item,*pwork_item;
dwordwinapiworkerthread(pvoidpparam)
{
pthread_poolpthreadpool=(pthread_pool)pparam;
handleevents[2];
events[0]=pthreadpool->quitevent;
events[1]=pthreadpool->workitemsemaphore;
for(;;)
{
dworddwret=waitformultipleobjects(2,events,false,infinite);
if(dwret==wait_object_0)
break;
//
//executeuser'sproc.
//
elseif(dwret==wait_object_0+1)
{
pwork_itempworkitem;
plist_entryplist;
entercriticalsection(&pthreadpool->workitemlock);
_assert(!islistempty(&pthreadpool->workitemheader));
plist=removeheadlist(&pthreadpool->workitemheader);
leavecriticalsection(&pthreadpool->workitemlock);
pworkitem=containing_record(plist,work_item,list);
pworkitem->userproc(pworkitem->userparam);
interlockeddecrement(&pthreadpool->workitemcount);
free(pworkitem);
}
else
{
_assert(0);
break;
}
}
return0;
}
boolinitializethreadpool(pthread_poolpthreadpool,longthreadnum)
{
pthreadpool->quitevent=createevent(null,true,false,null);
pthreadpool->workitemsemaphore=createsemaphore(null,0,0x7fffffff,null);
pthreadpool->workitemcount=0;
initializelisthead(&pthreadpool->workitemheader);
initializecriticalsection(&pthreadpool->workitemlock);
pthreadpool->threadnum=threadnum;
pthreadpool->threadsarray=(handle*)malloc(sizeof(handle)*threadnum);
for(inti=0;i<threadnum;i++)
{
pthreadpool->threadsarray[i]=createthread(null,0,workerthread,pthreadpool,0,null);
}
returntrue;
}
voiddestroythreadpool(pthread_poolpthreadpool)
{
setevent(pthreadpool->quitevent);
for(inti=0;i<pthreadpool->threadnum;i++)
{
waitforsingleobject(pthreadpool->threadsarray[i],infinite);
closehandle(pthreadpool->threadsarray[i]);
}
free(pthreadpool->threadsarray);
closehandle(pthreadpool->quitevent);
closehandle(pthreadpool->workitemsemaphore);
deletecriticalsection(&pthreadpool->workitemlock);
while(!islistempty(&pthreadpool->workitemheader))
{
pwork_itempworkitem;
plist_entryplist;
plist=removeheadlist(&pthreadpool->workitemheader);
pworkitem=containing_record(plist,work_item,list);
free(pworkitem);
}
}
boolpostworkitem(pthread_poolpthreadpool,work_item_procuserproc,pvoiduserparam)
{
pwork_itempworkitem=(pwork_item)malloc(sizeof(work_item));
if(pworkitem==null)
returnfalse;
pworkitem->userproc=userproc;
pworkitem->userparam=userparam;
entercriticalsection(&pthreadpool->workitemlock);
inserttaillist(&pthreadpool->workitemheader,&pworkitem->list);
leavecriticalsection(&pthreadpool->workitemlock);
interlockedincrement(&pthreadpool->workitemcount);
releasesemaphore(pthreadpool->workitemsemaphore,1,null);
returntrue;
}
voiduserproc1(pvoiddwparam)
{
workitem(dwparam);
}
voidtestsimplethreadpool(boolbwaitmode,longthreadnum)
{
thread_poolthreadpool;
initializethreadpool(&threadpool,threadnum);
completeevent=createevent(null,false,false,null);
begintime=gettickcount();
itemcount=20;
for(inti=0;i<20;i++)
{
postworkitem(&threadpool,userproc1,(pvoid)bwaitmode);
}
waitforsingleobject(completeevent,infinite);
closehandle(completeevent);
destroythreadpool(&threadpool);
}
我们把工作项目放到一个队列中,用一个信号量通知线程池,线程池中任意一个线程取出工作项目来执行,执行完毕之后,线程返回线程池,继续等待新的工作项目。
线程池中线程的数量是固定的,预先创建好的,永久的线程,直到销毁线程池的时候,这些线程才会被销毁。
线程池中线程获得工作项目的机会是均等的,随机的,并没有特别的方式保证哪一个线程具有特殊的优先获得工作项目的机会。
而且,同一时刻可以并发运行的线程数目没有任何限定。事实上,在我们的执行计算任务的演示代码中,所有的线程都并发执行。
下面,我们再来看一下,完成同样的任务,系统提供的线程池是如何运作的。
dwordbegintime;
longitemcount;
handlecompleteevent;
intcompute()
{
srand(begintime);
for(inti=0;i<20*1000*1000;i++)
rand();
returnrand();
}
dwordwinapiworkitem(lpvoidlpparameter)
{
boolbwaitmode=(bool)lpparameter;
if(bwaitmode)
sleep(1000);
else
compute();
if(interlockeddecrement(&itemcount)==0)
{
printf("timetotal%dsecond.\n",gettickcount()-begintime);
setevent(completeevent);
}
return0;
}
voidtestworkitem(boolbwaitmode,dwordflag)
{
completeevent=createevent(null,false,false,null);
begintime=gettickcount();
itemcount=20;
for(inti=0;i<20;i++)
{
queueuserworkitem(workitem,(pvoid)bwaitmode,flag);
}
waitforsingleobject(completeevent,infinite);
closehandle(completeevent);
}
很简单,是吧?我们仅需要关注于我们的回调函数即可。但是与我们的简单模拟来比,系统提供的线程池有着更多的优点。
首先,线程池中线程的数目是动态调整的,其次,线程池利用io完成端口的特性,它可以限制并发运行的线程数目,默认情况下,将会限制为cpu的数目,这可以减少线程切换。它挑选最近执行过的线程再次投入执行,从而避免了不必要的线程切换。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯