国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

關于線程同步的一些方法

2019-11-18 18:43:52
字體:
來源:轉載
供稿:網友
線程是進程內一個相對獨立的、可調度的執行單元。一個應用可以有一個主線程,一個主線程可以有多個子線程,子線程還可以有自己的子線程,這樣就構成了多線程應用了。由于多個線程往往會同時訪問同一塊內存區域,頻繁的訪問這塊區域,將會增加產生線程沖突的概率。一旦產生了沖突,將會造成不可預料的結果(該公用區域的值是不可預料的)可見處理線程同步的必要性。
 
注意:本文中出現的所有代碼都是用DELPHI描述的,調試環境為Windows me ,Delphi 6。其中所涉及的Windows API函數可以從MSDN獲得詳細的文檔。
 
首先引用一個實例來引出我們以下的討論,該實例沒有采取任何措施來避免線程沖突,它的主要過程為:由主線程啟動兩個線程對letters這個全局變量進行頻繁的讀寫,然后分別把修改的結果顯示到ListBox中。由于沒有同步這兩個線程,使得線程在修改letters時產生了不可預料的結果。大家可以看看它運行的結果,如圖:
ListBox中的每一行的字母都應該一致,但是上圖畫線處則不同,這就是線程沖突產生的結果。當兩個線程同時訪問該共享內存時,一個線程還未對該內存修改完,另一個線程又對該內存進行了修改,由于寫值的過程沒有被串行化,這樣就產生了無效的結果。可見線程同步的重要性。
 
以下是本例的代碼
unit.pas文件
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
 
//定義窗口類
type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    Button1: TButton;
    PRocedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
//定義線程類
type
  TListThread=class(TThread)
  private
    Str:String;
  protected
    procedure AddToList;//將Str加入ListBox組件
    Procedure Execute;override;
  public
    LBox:TListBox;
end;
//定義變量
var
  Form1: TForm1;
  Letters:String='AAAAAAAAAAAAAAAAAAAA';//全局變量
 
implementation
 
{$R *.dfm}
 
//線程類實現部分
procedure TListThread.Execute;
var
  I,J,K:Integer;
begin
  for i:=0 to 50 do
  begin
    for J:=1 to 20 do
      for K:=1 to 1000 do//循環1000次增加產生沖突的幾率
      if letters[j]<'Z' then
        letters[j]:=succ(Letters[j])
      else
        letters[j]:='A';
    str:=letters;
    synchronize(addtolist);//同步訪問VCL可視組件
    end;
end;
 
procedure TListThread.AddToList;
begin
  LBox.Items.Add(str);//將str加入列表框
end;
 
//窗口類實現部分
procedure TForm1.Button1Click(Sender: TObject);
var
  th1,th2:TListThread;
begin
  Listbox1.Clear;
  Listbox2.Clear;
  th1:=tlistThread.Create(true);//創建線程1
  th2:=tlistThread.Create(true);//創建線程2
  th1.LBox:=listBox1;
  th2.LBox:=listBox2;
  th1.Resume;//開始執行
  th2.Resume;
end;
end.
 
由上例可見,當多個線程同時修改一個公用變量時,會產生沖突,所以我們要設法防止它,這樣我們開發的多線程應用才能夠穩定地運行。下面我們來改進它。我們先使用臨界段來串行化,實現同步。在上例unit1.pas代碼的uses段中加入SyncObjs單元,加入全局臨界段變量(TRTLCriticalSection)Critical1,在FormCreate事件中加入InitializeCriticalSection(Critical1)這句代碼,在FormDestroy事件中加入DeleteCriticalSection(Critical1)這句代碼,然后修改TListThread.Execute函數,修改后的代碼似如下所示(►處為增加的代碼):
procedure TListThread.Execute;
var
  I,J,K:Integer;
begin
  for i:=0 to 50 do
  begin
    ►EnterCriticalSection(Critical1);//進入臨界段
    for J:=1 to 20 do
      for K:=1 to 3000 do
      if letters[j]<'Z' then
        letters[j]:=succ(Letters[j])
      else
        letters[j]:='A';
    str:=letters;
    ►LeaveCriticalSection(Critical1);//退出臨界段
    synchronize(addtolist);
    end;
end;
好了,重新編譯,運行結果如下圖所示:
程序成功的避免了沖突,看來真的很簡單,我們成功了!當然我們還可以使用其它同步技術如Mutex(互斥對象), Semaphore(信號量)等,這些技術都是Windows通過API直接提供給我們的。
 
下面總結一下Windows常用的幾種線程同步技術。
1.         Critical Sections(臨界段),源代碼中如果有不能由兩個或兩個以上線程同時執行的部分,可以用臨界段來使這部分的代碼執行串行化。它只能在一個獨立的進程或一個獨立的應用程序中使用。使用方法如下:
//在窗體創建中
InitializeCriticalSection(Critical1)
//
在窗體銷毀中
DeleteCriticalSection(Critical1)
//
在線程中
EnterCriticalSection(Critical1)
……
保護的代碼
LeaveCriticalSection(Critical1)
2.         Mutex(互斥對象),是用于串行化訪問資源的全局對象。我們首先設置互斥對象,然后訪問資源,最后釋放互斥對象。在設置互斥對象時,如果另一個線程(或進程)試圖設置相同的互斥對象,該線程將會停下來,直到前一個線程(或進程)釋放該互斥對象為止。注意它可以由不同應用程序共享。使用方法如下:
//在窗體創建中
hMutex:=CreateMutex(nil,false,nil)
//
在窗體銷毀中
CloseHandle(hMutex)
//
在線程中
WaitForSingleObject(hMutex,INFINITE)
……
保護的代碼
ReleaseMutex(hMutex)
3.         Semaphore(信號量),它與互斥對象相似,但它可以計數。例如可以允許一個給定資源同時同時被三個線程訪問。其實Mutex就是最大計數為一的Semaphore。使用方法如下:
//在窗體創建中
hSemaphore:= CreateSemaphore(nil,lInitialCount,lMaximumCount,lpName)
//在窗體銷毀中

CloseHandle(hSemaphore)
//
在線程中
WaitForSingleObject(hSemaphore,INFINITE)
……
保護的代碼
ReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount)
4.         還可以使用Delphi中的TcriticalSection這個VCL對象,它的定義在Syncobjs.pas中。
 
當你開發多線程應用時,并且多個線程同時訪問一個共享資源或數據時,你需要考慮線程同步的問題了。
如果你想獲得本文的電子版及其源代碼,那么請到http://codehunter.1yes.net 網站上下載.

上一篇:取得的Outlook目錄并在TTreeView里顯示出來

下一篇:淺析桌面精靈的實現

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

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 天镇县| 东兰县| 晴隆县| 盈江县| 竹山县| 京山县| 阳西县| 五家渠市| 沾益县| 嘉兴市| 新野县| 柳江县| 鹤壁市| 诸城市| 马尔康县| 密云县| 葫芦岛市| 泰和县| 松原市| 吉隆县| 文成县| 海晏县| 南乐县| 鄂温| 中方县| 阿尔山市| 长武县| 社会| 南召县| 昌都县| 大安市| 仙游县| 拉孜县| 泾川县| 黑河市| 郑州市| 荣成市| 太白县| 自贡市| 泰安市| 怀集县|