极速赛车APP下载

ccriticalsection调用2次_uploadify调用2次_java读取失败重试2次

电脑杂谈  发布时间:2019-09-24 03:04:17  来源:网络整理

ccriticalsection 调用 2次_java 调用失败重试2次_uploadify 调用2次

原文链接:SynchronizationinMultithreadedApplicationswithMFC

简介

本文分析基本的同步概念,并实际动手帮助新手把握多线程编程。本文的重点在各类同步方法。

基本概念

程执行过程中,或多或少都应该互相交互,这种交互行为有多种方式和种类。例如,一个线程在执行完它被赋予的任务后,通知另一个线程任务终于完成。然后第二个线程做开始剩下的工作。

以下对象是用来支持同步的:

1)信号量

2)互斥锁

3)关键区域

4)事件

每个对象都有不同的目的和功能,但基本目的都是支持同步。当然也有其它可以拿来同步的对象,比如进程和线程对象。后二者的使用由程序员决定,比如说判定一个给定进程或轮询是否执行完毕为了使用进程和线程对象来进行同步,我们通常使用Wait*变量,在使用这种函数时,你应该明白一个概念,任何被成为同步对象的内核对象(关键区域除外)都进入两种状况之一:通知状态和未通知状态。例如,进程和线程对象,当人们起初执行时进入未通知状态,而当人们执行完毕时进入通知状态,

极速赛车APP下载为了判定一个给定进程或线程能否已经结束,我们需要判定表示其的对象能否进入通知状态,而要超过这种的目的,我们应该使用Wait*函数。

Wait*函数

上面是最简单的Wait*函数:

DWORDWaitForSingleObject

(

HANDLEhHandle,

DWORDdwMilliseconds

);

参数hHandle表示待检测其状况(通知以及未通知)的对象,dwMilliseconds表示读取线程在被检测对象处于其通知状态前必须期待的时间。若对象进入通知状态或选定时间过去了,这个变量返回控制权给调用线程。若dwMilliseconds设置为INIFINITE(值为-1),则调用线程会经常期待直到对象状况变为通知,这有也许促使调用线程依然期待下去,导致“饿死”。

比如,检查指定线程是否正在执行,dwMilliseconds设置为0,是为了让调用线程立即返回。

DWORDdw=WaitForSingleObject(hProcess,0);

switch(dw)

{

caseWAIT_OBJECT_0:

//theprocesshasexited

break;

caseWAIT_TIMEOUT:

//theprocessisstillexecuting

break;

极速赛车APP下载caseWAIT_FAILED:

//failure

break;

}

下一个Wait类函数类似下面的,但它带的是一系列句柄,并且期待其中之一或全部开启已通知状态。

DWORDWaitForMultipleObjects

(

DWORDnCount,

极速赛车APP下载CONSTHANDLE*lpHandles,

BOOLfWaitAll,

DWORDdwMilliseconds

);

参数nCount表示待检测的句柄个数,lpHandles指向线程函数,若fWaitAll为TRUE,则期待所有的对象处于已通知状态,若为FALSE,则当任何一个对象处于已通知状态时,函数返回。dwMilliseconds意义同上。

比如,下面代码判断哪些进程会先结束:

HANDLEh[3];

h[0]=hThread1;

h[1]=hThread2;

h[2]=hThread3;

DWORDdw=WaitForMultipleObjects(3,h,FALSE,5000);//任何一个处于已通知就返回

switch(dw)

{

极速赛车APP下载caseWAIT_FAILED:

//failure

break;

caseWAIT_TIMEOUT:

//noprocessesexitedduring5000ms

break;

caseWAIT_OBJECT_0+0:

//aprocesswithh[0]descriptorhasexited

break;

caseWAIT_OBJECT_0+1:

//aprocesswithh[1]descriptorhasexited

break;

caseWAIT_OBJECT_0+2:

//aprocesswithh[2]descriptorhasexited

break;

}

字段赋值中索引号为index的对象处于已通知状态时,函数返回WAIT_OBJECT_0+索引号。若fWaitAll为TRUE,则当所有对象处于已通知状态时,函数返回WAIT_OBJECT_0。

一个泛型若调用一个Wait*数组,则它从用户方式切换为内核机制。这带给的后果有好有坏。不好的是切换开启内核机制一般应该1000个时钟周期,这消耗不算小。好的是当开启内核机制后,就不应该使用处理器,而是处于休眠态,不参与处置器的调度了。

ccriticalsection 调用 2次_uploadify 调用2次_java 调用失败重试2次

今天让我们开启MFC,并看看它能为我们做些哪些。这里有两个类封装了对Wait*数组的调用:CSingleLock和CMultiLock。

每个类都从一个类--CSyncObject继承下来,此类最有用的成员是重载的HANDLE运算符,它返回选定同步对象的内在句柄。所有那些类都定义在<AfxMt.h>头文件中。

事件

通常来说,事件用于这种的情形下:当指定的动作出现后,一个线程(或多个线程)才开始执行其任务。例如,一个线程可能期待必需的数据收集完后才开始将其保存到硬盘上。有两种事件:手动重置型和自动重置型。通过使用事件,我们可以轻松地通知另一个线程特定的动作早已出现了。对于自动重置型事件,线程使用它通知多个线程特定动作已然出现,而针对手动重置型事件,线程使用它只可以通知一个线程。在MFC中,CEvent类封装了事件对象(若在win32中,它是用一个HANDLE来表示的)。CEvent的构造变量运行我们选用创建手动重置型和自动重置型事件。默认的建立类型是手动重置型事件。为了通知正在期待的线程,我们可以读取CEvent::SetEvent方法,这个方式必将让事件开启已通知状态。若事件是自动重置型,则事件会维持已通知状态,直到对应的CEvent::ResetEvent被调用,这个办法将促使事件开启未通知状态。这个特点从而一个线程可以借助一个SetEvent调用去通知多个线程。若事件是手动重置型,则所有正在期待的线程中唯有一个线程会接收到通知。当那些线程接收到通知后,事件会自动开启未通知状态。

上面两个实例将展现上述特点:

//createanauto-resetevent

CEventg_eventStart;

UINTThreadProc1(LPVOIDpParam)

{

极速赛车APP下载::WaitForSingleObject(g_eventStart,INFINITE);

return0;

}

极速赛车APP下载UINTThreadProc2(LPVOIDpParam)

{

::WaitForSingleObject(g_eventStart,INFINITE);

return0;

}

在这个示例中,一个全局的CEvent对象被建立,当然它是手动重置型的。除此以外,有两个工作线程在期待这个事件对象从而开始其工作。只要第三个线程调用哪个事件对象的SetEvent方法,则两个线程中之一(也许没人了解会是什么)会接收到通知,然后事件会开启未通知状态,这就避免了第二个线程也受到事件的通知。

上面来看第二个示例:

//createamanual-resetevent

CEventg_eventStart(FALSE,TRUE);

UINTThreadProc1(LPVOIDpParam)

{

::WaitForSingleObject(g_eventStart,INFINITE);

return0;

}

UINTThreadProc2(LPVOIDpParam)

{

::WaitForSingleObject(g_eventStart,INFINITE);

return0;

}

这段代码和前面的稍有不同,CEvent对象构造变量的参数不一样了,但意义上就大不同了,这是一个自动重置型事件对象。若第三个线程调用事件对象的SetEvent方法,则可以保证两个工作线程都会同时(几乎是同时)起初工作。这是由于自动重置型事件在开启已通知状态后,会维持此状况直到对应的ResetEvent被调用。

除此以外事件对象也有一个办法:CEvent::PulseEvent。这个办法首先并且事件对象处于已通知状态,然后使其退回到未通知状态。若事件是自动重置型,事件开启已通知状态会让所有正在期待的线程得到通知ccriticalsection 调用 2次ccriticalsection 调用 2次,然后事件开启未通知状态。若事件是手动重置型,事件开启已通知状态时只会让所有期待的线程之一受到通知。若没有线程在期待,则调用ResetEvent什么也不干。

实例---工作者线程

本文所带的事例中,作者将展现怎样建立工作者线程或者怎么合理地销毁他们。作者定义了一个被所有泛型使用的控制变量。当单击视图区域时,就建立一个线程。所有被建立的泛型使用上述控制变量在视图客户区绘制一个运动的圆形。这里作者使用了一个自动重置型事件,它被拿来通知所有工作线程其“死讯”。除此以外,我们将发现怎么使得主线程等待直至所有工作者线程销毁掉。

作者将泛型数组定义为全局的:

structTHREADINFO

{

HWNDhWnd;//主视图区

POINTpoint;//起始点

};

UINTThreadDraw(PVOIDpParam);

externCEventg_eventEnd;

UINTThreadDraw(PVOIDpParam)

{

极速赛车APP下载staticintsnCount=0;//线程计数器

snCount++;//计数器递增

TRACE(TEXT("-ThreadDraw%d:started\n"),snCount);

//取出传入的参数

THREADINFO*pInfo=reinterpret_cast<THREADINFO*>(pParam);

CWnd*pWnd=CWnd::FromHandle(pInfo->hWnd);//主视图区

CClientDCdc(pWnd);

极速赛车APP下载intx=pInfo->point.x;

inty=pInfo->point.y;

srand((UINT)time(NULL));

java 调用失败重试2次_uploadify 调用2次_ccriticalsection 调用 2次

CRectrectEllipse(x-25,y-25,x+25,y+25);

CSizesizeOffset(1,1);

//刷子颜色随机

CBrushbrush(RGB(rand()%256,rand()%256,rand()%256));

CBrush*pOld=dc.SelectObject(&brush);

while(WAIT_TIMEOUT==::WaitForSingleObject(g_eventEnd,0))

{//即使主线程还未通知我自杀,继续工作!(注意时间设置为)

CRectrectClient;

pWnd->GetClientRect(rectClient);

if(rectEllipse.left<rectClient.left||rectEllipse.right>rectClient.right)

sizeOffset.cx*=-1;

if(rectEllipse.top<rectClient.top||rectEllipse.bottom>rectClient.bottom)

sizeOffset.cy*=-1;

dc.FillRect(rectEllipse,CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

rectEllipse.OffsetRect(sizeOffset);

dc.Ellipse(rectEllipse);

Sleep(25);//休眠下,给其它绘制子线程运行的机会

}

dc.SelectObject(pOld);


本文来自电脑杂谈,转载请注明本文网址:
http://www.0531mai.com/a/jisuanjixue/article-123935-1.html

相关阅读
发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

极速赛车手机版下载 极速赛车APP下载 极速赛车APP下载 极速赛车手机官网 极速赛车APP 极速赛车APP 极速赛车APP 极速赛车双面盘 极速赛车手机官网 极速赛车APP