亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

Delphi中的線程類--之(4)

2019-11-18 18:28:02
字體:
來源:轉載
供稿:網友
 

Delphi中的線程類

 

猛禽[Mental Studio]

http://mental.mentsu.com

 

之四

臨界區(CriticalSection)則是一項共享數據訪問保護的技術。它其實也是相當于一個全局的布爾變量。但對它的操作有所不同,它只有兩個操作:EnterLeave,同樣可以把它的兩個狀態當作TrueFalse,分別表示現在是否處于臨界區中。這兩個操作也是原語,所以它可以用于在多線程應用中保護共享數據,防止訪問沖突。

用臨界區保護共享數據的方法很簡單:在每次要訪問共享數據之前調用Enter設置進入臨界區標志,然后再操作數據,最后調用Leave離開臨界區。它的保護原理是這樣的:當一個線程進入臨界區后,如果此時另一個線程也要訪問這個數據,則它會在調用Enter時,發現已經有線程進入臨界區,然后此線程就會被掛起,等待當前在臨界區的線程調用Leave離開臨界區,當另一個線程完成操作,調用Leave離開后,此線程就會被喚醒,并設置臨界區標志,開始操作數據,這樣就防止了訪問沖突。

以前面那個InterlockedIncrement為例,我們用CriticalSectionWindows API)來實現它:

Var

  InterlockedCrit : TRTLCriticalSection;

PRocedure InterlockedIncrement( var aValue : Integer );

Begin

  EnterCriticalSection( InterlockedCrit );

  Inc( aValue );

  LeaveCriticalSection( InterlockedCrit );

End;

現在再來看前面那個例子:

1.         線程A進入臨界區(假設數據為3

2.         線程B進入臨界區,因為A已經在臨界區中,所以B被掛起

3.         線程A對數據加一(現在是4

4.         線程A離開臨界區,喚醒線程B(現在內存中的數據是4

5.         線程B被喚醒,對數據加一(現在就是5了)

6.         線程B離開臨界區,現在的數據就是正確的了。

臨界區就是這樣保護共享數據的訪問。

關于臨界區的使用,有一點要注意:即數據訪問時的異常情況處理。因為如果在數據操作時發生異常,將導致Leave操作沒有被執行,結果將使本應被喚醒的線程未被喚醒,可能造成程序的沒有響應。所以一般來說,如下面這樣使用臨界區才是正確的做法:

EnterCriticalSection

Try

   //  操作臨界區數據

Finally

  LeaveCriticalSection

End;

 

最后要說明的是,EventCriticalSection都是操作系統資源,使用前都需要創建,使用完后也同樣需要釋放。如TThread類用到的一個全局EventSyncEvent和全局CriticalSectionTheadLock,都是在InitThreadSynchronizationDoneThreadSynchronization中進行創建和釋放的,而它們則是在Classes單元的InitializationFinalization中被調用的。

由于在TThread中都是用API來操作EventCriticalSection的,所以前面都是以API為例,其實Delphi已經提供了對它們的封裝,在SyncObjs單元中,分別是TEvent類和TCriticalSection類。用法也與前面用API的方法相差無幾。因為TEvent的構造函數參數過多,為了簡單起見,Delphi還提供了一個用默認參數初始化的Event類:TSimpleEvent。

順便再介紹一下另一個用于線程同步的類:TMultiReadExclusiveWriteSynchronizer,它是在SysUtils單元中定義的。據我所知,這是Delphi RTL中定義的最長的一個類名,還好它有一個短的別名:TMREWSync。至于它的用處,我想光看名字就可以知道了,我也就不多說了。

 

有了前面對EventCriticalSection的準備知識,可以正式開始討論SynchronizeWaitFor了。

 

我們知道,Synchronize是通過將部分代碼放到主線程中執行來實現線程同步的,因為在一個進程中,只有一個主線程。先來看看Synchronize的實現:

procedure TThread.Synchronize(Method: TThreadMethod);

begin

  FSynchronize.FThread := Self;

  FSynchronize.FSynchronizeException := nil;

  FSynchronize.FMethod := Method;

  Synchronize(@FSynchronize);

end;

其中FSynchronize是一個記錄類型:

  PSynchronizeRecord = ^TSynchronizeRecord;

  TSynchronizeRecord = record

    FThread: TObject;

    FMethod: TThreadMethod;

    FSynchronizeException: TObject;

  end;

用于進行線程和主線程之間進行數據交換,包括傳入線程類對象,同步方法及發生的異常。

Synchronize中調用了它的一個重載版本,而且這個重載版本比較特別,它是一個“類方法”。所謂類方法,是一種特殊的類成員方法,它的調用并不需要創建類實例,而是像構造函數那樣,通過類名調用。之所以會用類方法來實現它,是因為為了可以在線程對象沒有創建時也能調用它。不過實際中是用它的另一個重載版本(也是類方法)和另一個類方法StaticSynchronize。下面是這個Synchronize的代碼:

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);

var

  SyncProc: TSyncProc;

begin

  if GetCurrentThreadID = MainThreadID then

    ASyncRec.FMethod

  else

  begin

    SyncProc.Signal := CreateEvent(nil, True, False, nil);

    try

      EnterCriticalSection(ThreadLock);

      try

        if SyncList = nil then

          SyncList := TList.Create;

        SyncProc.SyncRec := ASyncRec;

        SyncList.Add(@SyncProc);

        SignalSyncEvent;

        if Assigned(WakeMainThread) then

          WakeMainThread(SyncProc.SyncRec.FThread);

        LeaveCriticalSection(ThreadLock);

        try

          WaitForSingleObject(SyncProc.Signal, INFINITE);

        finally

          EnterCriticalSection(ThreadLock);

        end;

      finally

        LeaveCriticalSection(ThreadLock);

      end;

    finally

      CloseHandle(SyncProc.Signal);

    end;

    if Assigned(ASyncRec.FSynchronizeException) then raise ASyncRec.FSynchronizeException;

  end;

end;

這段代碼略多一些,不過也不算太復雜。

首先是判斷當前線程是否是主線程,如果是,則簡單地執行同步方法后返回。

如果不是主線程,則準備開始同步過程。

通過局部變量SyncProc記錄線程交換數據(參數)和一個Event Handle,其記錄結構如下:

  TSyncProc = record

    SyncRec: PSynchronizeRecord;

    Signal: THandle;

  end;

然后創建一個Event,接著進入臨界區(通過全局變量ThreadLock進行,因為同時只能有一個線程進入Synchronize狀態,所以可以用全局變量記錄),然后就是把這個記錄數據存入SyncList這個列表中(如果這個列表不存在的話,則創建它)。可見ThreadLock這個臨界區就是為了保護對SyncList的訪問,這一點在后面介紹CheckSynchronize時會再次看到。

再接下就是調用SignalSyncEvent,其代碼在前面介紹TThread的構造函數時已經介紹過了,它的功能就是簡單地將SyncEvent作一個Set的操作。關于這個SyncEvent的用途,將在后面介紹WaitFor時再詳述。

接下來就是最主要的部分了:調用WakeMainThread事件進行同步操作。WakeMainThread是一個TNotifyEvent類型的全局事件。這里之所以要用事件進行處理,是因為Synchronize方法本質上是通過消息,將需要同步的過程放到主線程中執行,如果在一些沒有消息循環的應用中(如ConsoleDLL)是無法使用的,所以要使用這個事件進行處理。

而響應這個事件的是application對象,下面兩個方法分別用于設置和清空WakeMainThread事件的響應(來自Forms單元):

procedure TApplication.HookSynchronizeWakeup;

begin

  Classes.WakeMainThread := WakeMainThread;

end;

 

procedure TApplication.UnhookSynchronizeWakeup;

begin

  Classes.WakeMainThread := nil;

end;

上面兩個方法分別是在TApplication類的構造函數和析構函數中被調用。

這就是在Application對象中WakeMainThread事件響應的代碼,消息就是在這里被發出的,它利用了一個空消息來實現:

procedure TApplication.WakeMainThread(Sender: TObject);

begin

  PostMessage(Handle, WM_NULL, 0, 0);

end;

而這個消息的響應也是在Application對象中,見下面的代碼(刪除無關的部分):

procedure TApplication.WndProc(var Message: TMessage);

begin

  try

    with Message do

      case Msg of

        WM_NULL:

          CheckSynchronize;

  except

    HandleException(Self);

  end;

end;

其中的CheckSynchronize也是定義在Classes單元中的,由于它比較復雜,暫時不詳細說明,只要知道它是具體處理Synchronize功能的部分就好,現在繼續分析Synchronize的代碼。

在執行完WakeMainThread事件后,就退出臨界區,然后調用WaitForSingleObject開始等待在進入臨界區前創建的那個Event。這個Event的功能是等待這個同步方法的執行結束,關于這點,在后面分析CheckSynchronize時會再說明。

注意在WaitForSingleObject之后又重新進入臨界區,但沒有做任何事就退出了,似乎沒有意義,但這是必須的!

因為臨界區的EnterLeave必須嚴格的一一對應。那么是否可以改成這樣呢:

        if Assigned(WakeMainThread) then

          WakeMainThread(SyncProc.SyncRec.FThread);

        WaitForSingleObject(SyncProc.Signal, INFINITE);

      finally

        LeaveCriticalSection(ThreadLock);

      end;

上面的代碼和原來的代碼最大的區別在于把WaitForSingleObject也納入臨界區的限制中了??瓷先]什么影響,還使代碼大大簡化了,但真的可以嗎?

事實上是不行!

因為我們知道,在Enter臨界區后,如果別的線程要再進入,則會被掛起。而WaitFor方法則會掛起當前線程,直到等待別的線程SetEvent后才會被喚醒。如果改成上面那樣的代碼的話,如果那個SetEvent的線程也需要進入臨界區的話,死鎖(Deadlock)就發生了(關于死鎖的理論,請自行參考操作系統原理方面的資料)。

死鎖是線程同步中最需要注意的方面之一!

最后釋放開始時創建的Event,如果被同步的方法返回異常的話,還會在這里再次拋出異常。

(待續)


上一篇:Delphi中的線程類--之(5,大結局)

下一篇:Delphi中的線程類--之(3)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产97在线精品一区| 91超碰中文字幕久久精品| 日韩亚洲精品视频| 一本色道久久综合狠狠躁篇的优点| 欧美午夜视频一区二区| 欧美极品少妇xxxxⅹ免费视频| 欧美成人免费小视频| 久久91亚洲精品中文字幕| 国产精品人成电影在线观看| 亚洲在线免费视频| 欧美精品一本久久男人的天堂| 51色欧美片视频在线观看| 欧美成人在线免费视频| 俺去啦;欧美日韩| 黄色一区二区在线| 亚洲国产成人91精品| 97免费在线视频| 欧美大片免费观看在线观看网站推荐| 欧美又大粗又爽又黄大片视频| 青青a在线精品免费观看| 久久影院中文字幕| 亚洲激情自拍图| 欧美激情va永久在线播放| 久久精品久久久久| 欧美裸体男粗大视频在线观看| 欧美日韩中文在线| 久久99久国产精品黄毛片入口| 日韩精品极品视频免费观看| 高潮白浆女日韩av免费看| 亚洲乱码一区av黑人高潮| 在线不卡国产精品| 精品国产91久久久久久老师| 伊是香蕉大人久久| 亚洲网站在线观看| 国产精品第七十二页| 超碰91人人草人人干| 精品动漫一区二区| 国产免费观看久久黄| 欧美又大粗又爽又黄大片视频| 最近2019中文字幕一页二页| 日韩美女写真福利在线观看| 国产精品吹潮在线观看| 欧美丝袜第一区| 国产精品久久久久久久久久小说| 欧美日韩国产91| 成人精品视频99在线观看免费| 欧美成人免费小视频| 97视频在线观看亚洲| 日本不卡视频在线播放| 奇米成人av国产一区二区三区| 九色91av视频| 欧美黑人一级爽快片淫片高清| 欧美高跟鞋交xxxxxhd| 国产一区二区在线免费视频| 成人国产精品久久久| 成人黄色网免费| 亚洲精品福利免费在线观看| 欧美精品性视频| 超碰97人人做人人爱少妇| 欧美成人亚洲成人| 国产精品久久久久福利| 亚洲国产精久久久久久| 91精品久久久久久久久久久久久久| 欧美日韩不卡合集视频| 黑人欧美xxxx| 国产欧亚日韩视频| 国产精品视频白浆免费视频| 久久亚洲精品中文字幕冲田杏梨| 国产精品久久久久9999| 欧美成人性色生活仑片| 57pao成人国产永久免费| 国产精品久久久久久久久久久新郎| 国产精品第100页| 亚洲桃花岛网站| 亚洲精品成人av| 日本久久久久亚洲中字幕| 国产免费亚洲高清| 日韩av手机在线看| 永久555www成人免费| 欧美成年人视频网站欧美| 亚洲中国色老太| 久久亚洲春色中文字幕| 2020欧美日韩在线视频| 亚洲精品720p| 日韩大片免费观看视频播放| 日韩欧美在线国产| 久久久国产精品x99av| 亚洲人成电影网站色| 国产剧情久久久久久| 国产专区欧美专区| 97视频在线观看免费| 91精品国产综合久久久久久久久| 国内精品小视频在线观看| 亚洲人成电影在线| 国产一区二区三区在线视频| 97高清免费视频| 91av视频在线免费观看| 欧美极品在线视频| 国产日本欧美一区二区三区在线| 国产精品亚洲精品| 国产精品自产拍高潮在线观看| 91人人爽人人爽人人精88v| 国产精品极品尤物在线观看| 狠狠色香婷婷久久亚洲精品| 国产亚洲欧美视频| 国产成人精品一区二区| 一本色道久久综合狠狠躁篇的优点| 日韩中文字在线| 国产精品美女在线观看| 国产精品香蕉在线观看| 亚洲一区免费网站| 国产一区二区黑人欧美xxxx| 精品久久久久久国产91| 欧美激情高清视频| 在线电影中文日韩| 亚洲第一精品夜夜躁人人爽| 高潮白浆女日韩av免费看| 欧美日韩中文字幕日韩欧美| 欧美激情免费在线| 美乳少妇欧美精品| 九九热这里只有在线精品视| 国产噜噜噜噜噜久久久久久久久| 国产精品日韩精品| 视频直播国产精品| 国产福利视频一区二区| 国产98色在线| 中文字幕亚洲专区| 自拍偷拍亚洲一区| 国产日韩欧美中文在线播放| 欧美日韩美女在线观看| 91理论片午午论夜理片久久| 久久99精品国产99久久6尤物| 久久久天堂国产精品女人| 国产欧美一区二区三区视频| 懂色av中文一区二区三区天美| 欧美午夜激情小视频| 日本最新高清不卡中文字幕| 茄子视频成人在线| 亚洲精品国产品国语在线| 亚洲国产精品一区二区久| 中文字幕日韩欧美精品在线观看| 久久久99久久精品女同性| 亚洲人成在线免费观看| 国产免费一区二区三区在线能观看| 精品福利免费观看| 国产极品精品在线观看| 国产精品av网站| 亚洲伊人成综合成人网| 91精品国产自产在线老师啪| 高清欧美性猛交xxxx黑人猛交| 成人妇女淫片aaaa视频| 欧美亚洲另类视频| 国产欧亚日韩视频| 成人性生交大片免费看小说| 欧美日韩成人免费| 久久91亚洲精品中文字幕| 国产精品白嫩初高中害羞小美女| 国产91精品黑色丝袜高跟鞋| 亚洲精品电影网站| 久久影院免费观看| 青草青草久热精品视频在线观看| 精品久久香蕉国产线看观看gif| 国产精品视频自拍| 亚洲国产一区二区三区四区|