當多個線程同時訪問共享資源或數據時,有必要考慮線程同步。Synchronize()在隱藏窗口中運行。如果您的任務在這裏很忙,您的主窗口將被阻塞。Synchronize()只是把這個線程的代碼放到主線程中運行,而不是線程同步。
臨界區是同步進程中所有線程的最佳方式。它不是系統級的,而是進程級的,這意味著它可能會在進程中使用壹些標誌來保證進程中線程的同步。
裏希特說這是壹個計數周期;關鍵區域只能在同壹流程中使用;臨界區只能無限期等待,但是2k增加了TryEnterCriticalSection函數。
數來實現0次等待。互斥是為了保證多個進程之間的線程同步,它使用系統內核對象來保證同步。因為系統內核對象可以被命名,所以多個
這個命名的內核對象可以在進程之間使用,以確保系統資源的線程安全。互斥體是Win32。
內核對象,由操作系統管理;互斥體可以使用WaitForSingleObject實現無限等待、零次等待和任意次等待。常見的線程同步方法如下:
1.判別區域
臨界區是線程同步最直接的方式。臨界區是壹段壹次只能由壹個線程執行的代碼。如果將初始化數組的代碼放在臨界區,則在第壹個線程完成處理之前,不會執行另壹個線程。使用方法如下:
//在表單創建中
initialize critical section(critical 1)
//以破壞的形式
刪除關鍵部分(關鍵部分1)
//在線程中
輸入關鍵部分(關鍵部分1)
.....受保護的代碼。
leave critical section(critical 1)
2.互斥的
互斥體與臨界區非常相似,除了兩個關鍵區別:首先,互斥體可以用於跨進程的線程同步。第二,可以給互斥體壹個字符串名,通過引用這個名稱可以創建現有互斥體對象的額外句柄。
臨界區和事件對象(比如互斥體)之間最大的區別在於性能。臨界段沒有線程沖突時,用10 ~
15個時間片,而事件對象因為涉及系統內核,需要400~600個時間片。
互斥體(Mutex)是壹個全局對象,用於序列化對資源的訪問。我們首先設置互斥,然後訪問資源,最後釋放互斥。當設置互斥體時,如果另壹個線程(或進程)試圖設置相同的互斥體,該線程將停止,直到前壹個線程(或進程)釋放互斥體。請註意,它可以由不同的應用程序共享。使用方法如下:
//在表單創建中
hMutex:=CreateMutex(nil,false,nil)
//以破壞的形式
CloseHandle(hMutex)
//在線程中
WaitForSingleObject(hMutex,INFINITE)
.....受保護的代碼。
釋放互斥(hMutex)
3.旗語
另壹種同步線程的技術是使用信號量對象。它建立在互斥的基礎上,但信號量增加了資源計數的功能,允許預定數量的線程同時進入要同步的代碼。可以用CreateSemaphore()創建壹個信號量對象。
因為只允許壹個線程進入要同步的代碼,所以信號量的最大計數值(lMaximumCount)應該設置為1。事實上,互斥體是壹個最大計數為1的信號量。使用方法如下:
//在表單創建中
hSemaphore:= CreateSemaphore(nil,lInitialCount,lMaximumCount,lpName)
//以破壞的形式
關閉句柄(hSemaphore)
//在線程中
WaitForSingleObject(hSemaphore,INFINITE)
.....受保護的代碼。
ReleaseSemaphore(hSemaphore,lReleaseCount,lpPreviousCount)
4.返回值為4。WaitForSingleObject函數:
WAIT _ discarded指定的對象是壹個互斥體,擁有這個互斥體的線程在釋放這個對象之前已經終止。在這壹點上,互斥被認為是被放棄了。在這種情況下,互斥體屬於當前線程,並被設置為非信號狀態;
WAIT_OBJECT_0指定的對象處於信號狀態;
WAIT_TIMEOUT的等待時間已過,對象仍處於無信號狀態;
Delphi常用的TCriticalSection(Delphi)和TRtlCriticalSection。
TRtlCriticalSection是壹個結構,在windows單元中定義;
它是InitializeCriticalSection,EnterCriticalSection,LeaveCriticalSection,
這些kernel32.dll中關鍵區域操作API的參數,如DeleteCriticalSection
TCriticalSection是SyncObjs單元中實現的類,封裝了上述關鍵區域操作API函數,簡化和方便了在Delphi中的使用。如TCriticalSection。創建,TCriticalSection。進入,
TcriticalSection。離開等。;通過調用上面響應的API函數來實現。
在線程同步的各種方法中,使用臨界區是最簡單有效的方法(CPU占用時間最少)。
按如下方式使用關鍵區域代碼:
首先聲明壹個TRTLCriticalSection類型的全局變量。
定義變量
MyCs:TRTLCriticalSection;
在程序啟動或線程建立之前初始化。
InitializeCriticalSection(MyCs);//初始化臨界區
在程序結束或所有線程結束後刪除它。
DeleteCriticalSection(MyCs);//刪除關鍵區域
然後將其添加到要同步的線程中。
enter critical section(MyCs);//進入關鍵區域
嘗試
//程序代碼
最後
LeaveCriticalSection(MyCs);//離開關鍵區域
結束;
補充問題A->應用程序的同步。今天遇到的ProcessMessages:有壹個函數Fn可以分為a->;b-& gt;C
有三塊,其中B塊繪制各種窗口界面的操作比較復雜,耗時較長,應用。其中使用了ProcessMessages。程序運行測試時發現,如果在B中繪制窗口的進程完成之前調用Fn函數繪制其他窗口,程序可能會崩潰。起初,試圖用TcriticalSection變量來解決它是沒有用的。最後通過添加壹個全局變量來解決:定義壹個全局布爾變量標誌,設置初始值為True,將Fn函數的邏輯轉換為A->;
如果標誌然後
開始
flag:= False;
b;
flag:= True;
結束;
-& gt;C
問題成功解決。
順便總結壹下應用的功能。ProcessMessages:運行壹個非常耗時的循環,那麽在這個循環結束之前,程序可能不會響應任何事件,按鈕不會響應,程序設置也畫不出窗體,看起來像死了壹樣。這有時候是不方便的,比如沒有機會終止循環,又不想使用多線程的時候,那麽可以在循環中加入這句話,每次程序運行到這句話,程序都會讓系統響應消息。該函數類似於VB中的DoEvent方法。
調用ProcessMessages使應用程序在消息隊列中進行消息處理。ProcessMessages將循環Windows消息,直到消息為空,然後將控制權返回給應用程序。
註意:不要只在應用程序調用ProcessMessages時忽略消息處理效果,在其他應用程序中不要忽略。在冗長的操作中,定期調用ProcessMessages會導致應用程序響應畫筆或其他信息。
ProcessMessages不允許程序空閑,但HandleMessage允許。使用ProcessMessages時,必須確保可以重新輸入相關代碼。如果實在不行,也可以按照我上面的方法同步。