日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

當(dāng)有多個(gè)線程的時(shí)候,經(jīng)常需要去同步這些線程以訪問(wèn)同一個(gè)數(shù)據(jù)或資源。例如,假設(shè)有一個(gè)程序,其中一個(gè)線程用于把文件讀到內(nèi)存,而另一個(gè)線程用于統(tǒng)計(jì)文件中的字符數(shù)。當(dāng)然,在把整個(gè)文件調(diào)入內(nèi)存之前,統(tǒng)計(jì)它的計(jì)數(shù)是沒(méi)有意義的。但是,由于每個(gè)操作都有自己的線程,操作系統(tǒng)會(huì)把兩個(gè)線程當(dāng)作是互不相干的任務(wù)分別執(zhí)行,這樣就可能在沒(méi)有把整個(gè)文件裝入內(nèi)存時(shí)統(tǒng)計(jì)字?jǐn)?shù)。為解決此問(wèn)題,你必須使兩個(gè)線程同步工作。 
存在一些線程同步地址的問(wèn)題,Win32提供了許多線程同步的方式。在本節(jié)你將看到使用臨界區(qū)、 互斥、信號(hào)量和事件來(lái)解決線程同步的問(wèn)題。 

1. 臨界區(qū)
臨界區(qū)是一種最直接的線程同步方式。所謂臨界區(qū),就是一次只能由一個(gè)線程來(lái)執(zhí)行的一段代碼。如果把初始化數(shù)組的代碼放在臨界區(qū)內(nèi),另一個(gè)線程在第一個(gè)線程處理完之前是不會(huì)被執(zhí)行的。 
在使用臨界區(qū)之前,必須使用InitializeCriticalSection()過(guò)程來(lái)初始化它。 
其聲明如下:      procedure InitializeCriticalSection(varlpCriticalSection參數(shù)是一個(gè)TRTLCriticalSection類型的記錄,并且是變參。至于TRTLCriticalSection 是如何定義的,這并不重要,因?yàn)楹苌傩枰榭催@個(gè)記錄中的具體內(nèi)容。只需要在lpCriticalSection中傳遞未初始化的記錄,InitializeCriticalSection()過(guò)程就會(huì)填充這個(gè)記錄。 
注意Microsoft故意隱瞞了TRTLCriticalSection的細(xì)節(jié)。因?yàn)椋鋬?nèi)容在不同的硬件平臺(tái)上是不同的。在基于Intel的平臺(tái)上,TRTLCriticalSection包含一個(gè)計(jì)數(shù)器、一個(gè)指示當(dāng)前線程句柄的域和一個(gè)系統(tǒng)事件的句柄。在Alpha平臺(tái)上,計(jì)數(shù)器被替換為一種Alpha-CPU 數(shù)據(jù)結(jié)構(gòu),稱為spinlock。在記錄被填充后,我們就可以開(kāi)始創(chuàng)建臨界區(qū)了。這時(shí)我們需要用EnterCriticalSection()和LeaveCriticalSection()來(lái)封裝代碼塊。這兩個(gè)過(guò)程的聲明如下:     procedure EnterCriticalSection(var lpCriticalSection:TRRLCriticalSection);stdcall; 
procedure LeaveCriticalSection(var正如你所想的,參數(shù)lpCriticalSection就是由InitializeCriticalSection()填充的記錄。 
當(dāng)你不需要TRTLCriticalSection記錄時(shí),應(yīng)當(dāng)調(diào)用DeleteCriticalSection()過(guò)程,下面是它的聲明: procedure DeleteCriticalSection(var

2. 互斥
互斥非常類似于臨界區(qū),除了兩個(gè)關(guān)鍵的區(qū)別:首先,互斥可用于跨進(jìn)程的線程同步。其次,互斥能被賦予一個(gè)字符串名字,并且通過(guò)引用此名字創(chuàng)建現(xiàn)有互斥對(duì)象的附加句柄。 
提示臨界區(qū)與事件對(duì)象(比如互斥對(duì)象)的最大的區(qū)別是在性能上。臨界區(qū)在沒(méi)有線程沖突時(shí),要用1 0 ~ 1 5個(gè)時(shí)間片,而事件對(duì)象由于涉及到系統(tǒng)內(nèi)核要用400~600個(gè)時(shí)間片。 
可以調(diào)用函數(shù)CreateMutex ( )來(lái)創(chuàng)建一個(gè)互斥量。下面是函數(shù)的聲明: function
lpMutexAttributes參數(shù)為一個(gè)指向TSecurityAttributtes記錄的指針。此參數(shù)通常設(shè)為0,表示默認(rèn)的安全屬性。bInitalOwner參數(shù)表示創(chuàng)建互斥對(duì)象的線程是否要成為此互斥對(duì)象的擁有者。當(dāng)此參數(shù)為False時(shí), 表示互斥對(duì)象沒(méi)有擁有者。 
lpName參數(shù)指定互斥對(duì)象的名稱。設(shè)為nil表示無(wú)命名,如果參數(shù)不是設(shè)為nil,函數(shù)會(huì)搜索是否有同名的互斥對(duì)象存在。如果有,函數(shù)就會(huì)返回同名互斥對(duì)象的句柄。否則,就新創(chuàng)建一個(gè)互斥對(duì)象并返回其句柄。 
當(dāng)使用完互斥對(duì)象時(shí),應(yīng)當(dāng)調(diào)用CloseHandle()來(lái)關(guān)閉它。 

在程序中使用WaitForSingleObject()來(lái)防止其他線程進(jìn)入同步區(qū)域的代碼。此函數(shù)聲明如下: function

這個(gè)函數(shù)可以使當(dāng)前線程在dwMilliseconds指定的時(shí)間內(nèi)睡眠,直到hHandle參數(shù)指定的對(duì)象進(jìn)入發(fā)信號(hào)狀態(tài)為止。一個(gè)互斥對(duì)象不再被線程擁有時(shí),它就進(jìn)入發(fā)信號(hào)狀態(tài)。當(dāng)一個(gè)進(jìn)程要終止時(shí),它就進(jìn)入發(fā)信號(hào)狀態(tài)。dwMilliseconds參數(shù)可以設(shè)為0,這意味著只檢查hHandle參數(shù)指定的對(duì)象是否處于發(fā)信號(hào)狀態(tài),而后立即返回。dwMilliseconds參數(shù)設(shè)為INFINITE,表示如果信號(hào)不出現(xiàn)將一直等下去。 
這個(gè)函數(shù)的返回值如下 
WaitFor SingleObject()函數(shù)使用的返回值 
返回值 含義 
WAIT_ABANDONED 指定的對(duì)象是互斥對(duì)象,并且擁有這個(gè)互斥對(duì)象的線程在沒(méi)有釋放此對(duì)象之前就已終止。此時(shí)就稱互斥對(duì)象被拋棄。這種情況下,這個(gè)互斥對(duì)象歸當(dāng)前線程所有,并把它設(shè)為非發(fā)信號(hào)狀態(tài) 
WAIT_OBJECT_0 指定的對(duì)象處于發(fā)信號(hào)狀態(tài) 
WAIT_TIMEOUT等待的時(shí)間已過(guò),對(duì)象仍然是非發(fā)信號(hào)狀態(tài)再次聲明,當(dāng)一個(gè)互斥對(duì)象不再被一個(gè)線程所擁有,它就處于發(fā)信號(hào)狀態(tài)。此時(shí)首先調(diào)用WaitForSingleObject()函數(shù)的線程就成為該互斥對(duì)象的擁有者,此互斥對(duì)象設(shè)為不發(fā)信號(hào)狀態(tài)。當(dāng)線程調(diào)用ReleaseMutex()函數(shù)并傳遞一個(gè)互斥對(duì)象的句柄作為參數(shù)時(shí),這種擁有關(guān)系就被解除,互斥對(duì)象重新進(jìn)入發(fā)信號(hào)狀態(tài)。 
注意除WaitForSingleObject()函數(shù)外,你還可以使用WaitForMultipleObject()和MsgWaitForMultipleObject()函數(shù),它們可以等待幾個(gè)對(duì)象變?yōu)榘l(fā)信號(hào)狀態(tài)。這兩個(gè)函數(shù)的詳細(xì)情況請(qǐng)看Win32 API聯(lián)機(jī)文檔。 

3. 信號(hào)量
另一種使線程同步的技術(shù)是使用信號(hào)量對(duì)象。它是在互斥的基礎(chǔ)上建立的,但信號(hào)量增加了資源計(jì)數(shù)的功能,預(yù)定數(shù)目的線程允許同時(shí)進(jìn)入要同步的代碼。可以用CreateSemaphore()來(lái)創(chuàng)建一個(gè)信號(hào)量對(duì)象,其聲明如下: function
和CreateMutex()函數(shù)一樣,CreateSemaphore()的第一個(gè)參數(shù)也是一個(gè)指向TSecurityAttribute s記錄的指針,此參數(shù)的缺省值可以設(shè)為nil。 
lInitialCount參數(shù)用來(lái)指定一個(gè)信號(hào)量的初始計(jì)數(shù)值,這個(gè)值必須在0和lMaximumCount之間。此參數(shù)大于0,就表示信號(hào)量處于發(fā)信號(hào)狀態(tài)。當(dāng)調(diào)用WaitForSingleObject()函數(shù)(或其他函數(shù))時(shí),此計(jì)數(shù)值就減1。當(dāng)調(diào)用ReleaseSemaphore()時(shí),此計(jì)數(shù)值加1。 
參數(shù)lMaximumCount指定計(jì)數(shù)值的最大值。如果這個(gè)信號(hào)量代表某種資源,那么這個(gè)值代表可用資源總數(shù)。 
參數(shù)lpName用于給出信號(hào)量對(duì)象的名稱,它類似于CreateMutex()函數(shù)的lpName參數(shù)。 

—————————————————————————————————————————— 

關(guān)于線程同步: 
Synchronize()是在一個(gè)隱蔽的窗口里運(yùn)行,如果在這里你的任務(wù)很繁忙,你的主窗口會(huì)阻塞掉;Synchronize()只是將該線程的代碼放到主線程中運(yùn)行,并非線程同步。 

臨界區(qū)是一個(gè)進(jìn)程里的所有線程同步的最好辦法,他不是系統(tǒng)級(jí)的,只是進(jìn)程級(jí)的,也就是說(shuō)他可能利用進(jìn)程內(nèi)的一些標(biāo)志來(lái)保證該進(jìn)程內(nèi)的線程同步,據(jù)Richter說(shuō)是一個(gè)記數(shù)循環(huán);臨界區(qū)只能在同一進(jìn)程內(nèi)使用;臨界區(qū)只能無(wú)限期等待,不過(guò)2k增加了TryEnterCriticalSection函數(shù)實(shí)現(xiàn)0時(shí)間等待。 

互斥則是保證多進(jìn)程間的線程同步,他是利用系統(tǒng)內(nèi)核對(duì)象來(lái)保證同步的。由于系統(tǒng)內(nèi)核對(duì)象可以是有名字的,因此多個(gè)進(jìn)程間可以利用這個(gè)有名字的內(nèi)核對(duì)象保證系統(tǒng)資源的線程安全性。互斥量是Win32 內(nèi)核對(duì)象,由操作系統(tǒng)負(fù)責(zé)管理;互斥量可以使用WaitForSingleObject實(shí)現(xiàn)無(wú)限等待,0時(shí)間等待和任意時(shí)間等待。

1. 臨界區(qū)
臨界區(qū)是一種最直接的線程同步方式。所謂臨界區(qū),就是一次只能由一個(gè)線程來(lái)執(zhí)行的一段代碼。如果把初始化數(shù)組的代碼放在臨界區(qū)內(nèi),另一個(gè)線程在第一個(gè)線程處理完之前是不會(huì)被執(zhí)行的。在使用臨界區(qū)之前,必須使用InitializeCriticalSection()過(guò)程來(lái)初始化它。 
在第一個(gè)線程調(diào)用了EnterCriticalSection()之后,所有別的線程就不能再進(jìn)入代碼塊。下一個(gè)線程要等第一個(gè)線程調(diào)用LeaveCriticalSection()后才能被喚醒。 

2. 互斥
互斥非常類似于臨界區(qū),除了兩個(gè)關(guān)鍵的區(qū)別:首先,互斥可用于跨進(jìn)程的線程同步。其次,互斥能被賦予一個(gè)字符串名字,并且通過(guò)引用此名字創(chuàng)建現(xiàn)有互斥對(duì)象的附加句柄。 
提示:臨界區(qū)與事件對(duì)象(比如互斥對(duì)象)的最大的區(qū)別是在性能上。臨界區(qū)在沒(méi)有線程沖突時(shí),要用10 ~ 15個(gè)時(shí)間片,而事件對(duì)象由于涉及到系統(tǒng)內(nèi)核要用400~600個(gè)時(shí)間片。 
當(dāng)一個(gè)互斥對(duì)象不再被一個(gè)線程所擁有,它就處于發(fā)信號(hào)狀態(tài)。此時(shí)首先調(diào)用WaitForSingleObject()函數(shù)的線程就成為該互斥對(duì)象的擁有者,此互斥對(duì)象設(shè)為不發(fā)信號(hào)狀態(tài)。當(dāng)線程調(diào)用ReleaseMutex()函數(shù)并傳遞一個(gè)互斥對(duì)象的句柄作為參數(shù)時(shí),這種擁有關(guān)系就被解除,互斥對(duì)象重新進(jìn)入發(fā)信號(hào)狀態(tài)。 
可以調(diào)用函數(shù)CreateMutex()來(lái)創(chuàng)建一個(gè)互斥量。當(dāng)使用完互斥對(duì)象時(shí),應(yīng)當(dāng)調(diào)用CloseHandle()來(lái)關(guān)閉它。 

3. 信號(hào)量
另一種使線程同步的技術(shù)是使用信號(hào)量對(duì)象。它是在互斥的基礎(chǔ)上建立的,但信號(hào)量增加了資源計(jì)數(shù)的功能,預(yù)定數(shù)目的線程允許同時(shí)進(jìn)入要同步的代碼。可以用CreateSemaphore()來(lái)創(chuàng)建一個(gè)信號(hào)量對(duì)象, 
因?yàn)橹辉试S一個(gè)線程進(jìn)入要同步的代碼,所以信號(hào)量的最大計(jì)數(shù)值(lMaximumCount)要設(shè)為1。ReleaseSemaphore()函數(shù)將使信號(hào)量對(duì)象的計(jì)數(shù)加1; 
記住,最后一定要調(diào)用CloseHandle()函數(shù)來(lái)釋放由CreateSemaphore()創(chuàng)建的信號(hào)量對(duì)象的句柄。 

WaitForSingleObject函數(shù)的返值: 
WAIT_ABANDONED指定的對(duì)象是互斥對(duì)象,并且擁有這個(gè)互斥對(duì)象的線程在沒(méi)有釋放此對(duì)象之前就已終止。此時(shí)就稱互斥對(duì)象被拋棄。這種情況下,這個(gè)互斥對(duì)象歸當(dāng)前線程所有,并把它設(shè)為非發(fā)信號(hào)狀態(tài); 
WAIT_OBJECT_0 指定的對(duì)象處于發(fā)信號(hào)狀態(tài); 
WAIT_TIMEOUT等待的時(shí)間已過(guò),對(duì)象仍然是非發(fā)信號(hào)狀態(tài); 

—————————————————————————————————————————————— 
VCL支持三種技術(shù)來(lái)達(dá)到這個(gè)目的: 
(2) 使用critical區(qū) 
如果對(duì)象沒(méi)有提高內(nèi)置的鎖定功能,需要使用critical區(qū),Critical區(qū)在同一個(gè)時(shí)間只也許一個(gè)線程進(jìn)入。為了使用Critical區(qū),產(chǎn)生一個(gè)TCriticalSection全局的實(shí)例。TcriticalSection有兩個(gè)方法,Acquire(阻止其他線程執(zhí)行該區(qū)域)和Release(取消阻止) 

  每個(gè)Critical區(qū)是與你想要保護(hù)的全局內(nèi)存相關(guān)聯(lián)。每個(gè)訪問(wèn)全局內(nèi)存的線程必須首先使用Acquire來(lái)保證沒(méi)有其他線程使用它。完成以后,線程調(diào)用Release方法,讓其他線程也可以通過(guò)調(diào)用Acquire來(lái)使用這塊全局內(nèi)存。 

  警告:Critical區(qū)只有在所有的線程都使用它來(lái)訪問(wèn)全局內(nèi)存,如果有線程直接調(diào)用內(nèi)存,而不通過(guò)Acquire,會(huì)造成同時(shí)訪問(wèn)的問(wèn)題。例如:LockXY是一個(gè)全局的Critical區(qū)變量。任何一個(gè)訪問(wèn)全局X, Y的變量的線程,在訪問(wèn)前,都必須使用Acquire LockXY.Acquire; { lock out other threads }
try
Y := sin(X); 
finally
LockXY.Release; 
end臨界區(qū)主要是為實(shí)現(xiàn)線程之間同步的,但是使用的時(shí)候注意,一定要在用此臨界對(duì)象同步的線程之外建立該對(duì)象(一般在主線程中建立臨界對(duì)象)。 

———————————————————————————————————————————————— 
線程同步使用臨界區(qū),進(jìn)程同步使用互斥對(duì)象。 

Delphi中封裝了臨界對(duì)象。對(duì)象名為T(mén)CriticalSection,使用的時(shí)候只要在主線程當(dāng)中建立這個(gè)臨界對(duì)象(注意一定要在需要同步的線程之外建立這個(gè)對(duì)象)。具體同步的時(shí)候使用Lock和Unlock即可。 
而進(jìn)程間同步建立互斥對(duì)象,則只需要建立一個(gè)互斥對(duì)象CreateMutex. 需要同步的時(shí)候只需要WaitForSingleObject(mutexhandle, INFINITE) unlock的時(shí)候只需要ReleaseMutex(mutexhandle);即可。 

有很多方法, 信號(hào)燈, 臨界區(qū), 互斥對(duì)象,此外, windows下還可以用全局原子,共享內(nèi)存等等. 在windows體系中, 讀寫(xiě)一個(gè)8位整數(shù)時(shí)原子的, 你可以依靠這一點(diǎn)完成互斥的方法. 對(duì)于能夠產(chǎn)生全局名稱的方法能夠可以在進(jìn)程間同步上(如互斥對(duì)象), 也可以用在線程間同步上;不能夠產(chǎn)生全局名稱的方法(如臨界區(qū))只能用在線程間同步上.

CreateEvent的用法

HANDLE     CreateEvent(   
        LPSECURITY_ATTRIBUTES     lpEventAttributes,     //     SD   
        BOOL     bManualReset,                                                 //     reset     type   
        BOOL     bInitialState,                                               //     initial     state   
        LPCTSTR     lpName                                                         //     object     name   
    );   
    該函數(shù)創(chuàng)建一個(gè)Event同步對(duì)象,并返回該對(duì)象的Handle   
    
    lpEventAttributes     一般為NULL   
    bManualReset               創(chuàng)建的Event是自動(dòng)復(fù)位還是人工復(fù)位     ,如果true,人工復(fù)位,   
    一旦該Event被設(shè)置為有信號(hào),則它一直會(huì)等到ResetEvent()API被調(diào)用時(shí)才會(huì)恢復(fù)   
    為無(wú)信號(hào).     如果為false,Event被設(shè)置為有信號(hào),則當(dāng)有一個(gè)wait到它的Thread時(shí),   
    該Event就會(huì)自動(dòng)復(fù)位,變成無(wú)信號(hào).   
    bInitialState             初始狀態(tài),true,有信號(hào),false無(wú)信號(hào)   
    lpName                           Event對(duì)象名   
    
    一個(gè)Event被創(chuàng)建以后,可以用OpenEvent()API來(lái)獲得它的Handle,用CloseHandle()   
    來(lái)關(guān)閉它,用SetEvent()或PulseEvent()來(lái)設(shè)置它使其有信號(hào),用ResetEvent()   
    來(lái)使其無(wú)信號(hào),用WaitForSingleObject()或WaitForMultipleObjects()來(lái)等待   
    其變?yōu)橛行盘?hào).   
    
    PulseEvent()是一個(gè)比較有意思的使用方法,正如這個(gè)API的名字,它使一個(gè)Event   
    對(duì)象的狀態(tài)發(fā)生一次脈沖變化,從無(wú)信號(hào)變成有信號(hào)再變成無(wú)信號(hào),而整個(gè)操作是原子的.   
    對(duì)自動(dòng)復(fù)位的Event對(duì)象,它僅釋放第一個(gè)等到該事件的thread(如果有),而對(duì)于   
    人工復(fù)位的Event對(duì)象,它釋放所有等待的thread.

分享到:
標(biāo)簽:多線程 怎么處理 同步 delphi
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定