TCriticalSection TMutex TSpinlock TMonitor
直接上圖:運行結果如下:
如
代碼如下
:
unit Unit5;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs
,System.Diagnostics, FMX.ScrollBox, FMX.Memo, FMX.Controls.Presentation,
FMX.StdCtrls
,System.SyncObjs
,System.Threading;
type
TForm5 = class(TForm)
Multithreaded: TButton;
btnSingleThreaded: TButton;
MTwithlocking: TButton;
MTwithmutex: TButton;
MTwithTMonitor: TButton;
MTwithspinlock: TButton;
MTwithinterlocked: TButton;
Memo1: TMemo;
procedure btnSingleThreadedClick(Sender: TObject);
procedure MultithreadedClick(Sender: TObject);
procedure MTwithlockingClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure MTwithmutexClick(Sender: TObject);
procedure MTwithTMonitorClick(Sender: TObject);
procedure MTwithspinlockClick(Sender: TObject);
procedure MTwithinterlockedClick(Sender: TObject);
private
{ Private declarations }
FTimer: TStopwatch;
FValue:integer;
FLock: TCriticalSection;
FMutex: TMutex;
FSpinlock: TSpinlock;
procedure StartTimer;
procedure StopTimer;
procedure LogValue(const msg:string) ;
procedure IncValue;
procedure DecValue;
procedure RunInParallel(task1, task2: TProc);
procedure LockedIncValue;
procedure LockedDecValue;
procedure MutexIncValue;
procedure MutexDecValue;
procedure MonitorLockedIncValue;
procedure MonitorLockedDecValue;
procedure SpinlockIncValue;
procedure SpinlockDecValue ;
procedure InterlockedIncValue;
procedure InterlockedDecValue;
public
{ Public declarations }
end;
var
Form5: TForm5;
implementation
{$R *.fmx}
uses System.DateUtils;//調用單元文件 必須D MilliSecondsBetween(const ANow, AThen: TDateTime): Int64;
const
CNumRepeat = 10000000;
procedure TForm5.btnSingleThreadedClick(Sender: TObject);
begin
{按順序先后執行,先執行完加法運算后,再執行減法去運算;結果應當為0;
如果是同時運行又會有啥結果呢?請看---->多線程Multithreaded按鈕}
StartTimer;
FValue := 0;
IncValue;
DecValue;
StopTimer;
LogValue('Single threaded');
end;
procedure TForm5.StartTimer;
begin
FTimer := TStopwatch.StartNew;
end;
procedure TForm5.StopTimer;
begin
FTimer.Stop;
end;
procedure TForm5.LogValue(const msg:string) ;
begin
memo1.Lines.add(format('%S %D [%d 毫秒]',[msg ,FValue,FTimer.ElapsedMilliseconds]));
end;
procedure TForm5.IncValue;
var
i,value:integer;
begin
for i := 1 to CNumRepeat do begin
value := FValue;
FValue := value + 1;
end;
end;
procedure TForm5.DecValue;
var
i,value:integer;
begin
for i := 1 to CNumRepeat do
begin
value := FValue;
FValue := FValue - 1;
end;
end;
procedure TForm5.FormCreate(Sender: TObject);
begin
MEMO1.Lines.Add('正確的答案應當是 0');
end;
procedure TForm5.RunInParallel(task1, task2: TProc);
var
tast: array[0..1] of iTask; //System.Threading
begin
tast[0]:=TTASK.Run(task1) ;
tast[1]:=TTASK.Run(task2) ;
TTASK.WaitForAll(TAST);
end;
procedure TForm5.MultithreadedClick(Sender: TObject);
begin
StartTimer;
FValue := 0;
RunInParallel(IncValue, DecValue);
StopTimer;
LogValue('Multithreaded');
{執行結果如果是0,你可能也快中福利彩票特等獎了。
在任何給定的時間,有數百個線程在不同的程序中運行,並且它們都在爭奪有限數量的CPU核心。
名為同步並發,實則在同時在運行時,還要讓位給其它程序一定的時間,否則多任務的系統就
變成單任務的系統,返回到WINDOWS 3.0時代了。正如司機帶着老婆和老媽去游玩,2檔上路;
老婆和老媽同時要換檔:老婆要掛3檔,老媽掛到1檔。最終是掛到多少檔?
檔位就是共享的資源,多線程共享資源時,‘答案’是不確定的。
~
(~.~)
~
一定要同步,答案要確定,那又如何解決呢?請看往下看
}
end;
procedure TForm5.MTwithlockingClick(Sender: TObject);
begin
StartTimer;
FValue := 0;
FLock := TCriticalSection.Create; // ,System.SyncObjs
{臨界區對象TCriticalSection,向系統申請對下面代碼的特權}
try
RunInParallel(LockedIncValue, LockedDecValue);
finally
FreeAndNil(FLock); {用特權處理資源完畢,就得釋放特權,退還特權給系統!
防止蹲着茅坑不拉SHI }
end;
StopTimer;
LogValue('Critical section');
end;
procedure TForm5.LockedIncValue;
var
i,value:integer;
begin
for i := 1 to CNumRepeat do
begin
FLock.Acquire;//占着廁所;
value := FValue;
FValue := FValue + 1;
Flock.Release;////離開廁所,讓給下一位;
end;
end;
procedure TForm5.LockedDecValue;
var
i,value:integer;
begin
for i := 1 to CNumRepeat do
begin
FLock.Acquire;//占着廁所;
value := FValue;
FValue := FValue - 1;
Flock.Release;離開廁所,讓給下一位;
end;
end;
procedure TForm5.MTwithmutexClick(Sender: TObject);
begin
//互斥鎖 ,效率超級低,存在界面無響應問題 ,請繼續往下看
StartTimer;
FValue := 0;
FMutex := TMutex.Create(nil, false, '');
try
RunInParallel(MutexIncValue, MutexDecValue);
finally
//FreeAndNil(FLock); //原來
FreeAndNil(FMutex)
end;
StopTimer;
LogValue('Mutex');
end;
procedure TForm5.MutexIncValue;
var
i: integer;
value: integer;
begin
for i := 1 to CNumRepeat do begin
FMutex.Acquire;
value := FValue;
FValue := value + 1;
FMutex.Release;
end;
end;
procedure TForm5.MutexDecValue;
var
i: integer;
value: integer;
begin
for i := 1 to CNumRepeat do begin
FMutex.Acquire;
value := FValue;
FValue := value - 1;
FMutex.Release;
end;
end;
procedure TForm5.MTwithTMonitorClick(Sender: TObject);
begin
{它比TCriticalSection更快更簡單(您不必創建單獨的對象)。只有在真正使用共享對象時才應該使用TMonitor,
這樣就可以直接鎖定它。它不使用臨界區,而是一種名為spinlock的改進思想。}
StartTimer;
FValue := 0;
RunInParallel(MonitorLockedIncValue, MonitorLockedDecValue);
StopTimer;
LogValue('TMonitor');
end;
procedure TForm5.MonitorLockedIncValue;
var
value: integer;
i: Integer;
begin
for i := 1 to CNumRepeat do begin
System.TMonitor.Enter(Self);
value := FValue;
FValue := value + 1;
System.TMonitor.Exit(Self);
end;
end;
procedure Tform5.MonitorLockedDecValue;
var
value,i:integer;
begin
for i := 1 to CNumRepeat do
begin
try
system.TMonitor.Enter(SELF);
VALUE:=fvalue;
fvalue:=value-1;
system.TMonitor.Exit(self);
finally
end;
end;
end;
procedure TForm5.MTwithspinlockClick(Sender: TObject);
begin
{自旋鎖假定用它保護的代碼非常短,並且自旋鎖將被快速釋放。如果已經從另一個線程獲取了自旋鎖,則代碼首先嘗試主動等待或旋轉。代碼不是進入睡眠狀態,而是在緊密循環中運行,並不斷檢查自旋鎖是否可用。只有在一段時間后才發生這種情況,線程才會進入休眠狀態}
{TSpinLock是一個記錄,而不是一個對象,所以沒有必要釋放它。 您仍然需要創建它,因為一些數據在構造函數中初始化.
TSpinLock唯一的問題是它不是可重入的。 如果已經獲得自旋鎖的線程第二次調用Enter,則代碼將引發異常(如果已將True傳遞給構造函數)或阻塞。 但是,該實現提供了IsLocked和IsLockedByCurrentThread函數,您可以使用TSpinLock作為基函數來編寫可重入的自旋鎖。}
StartTimer;
FValue := 0;
FSpinlock := TSpinLock.Create(false);
RunInParallel(SpinlockIncValue, SpinlockDecValue);
StopTimer;
LogValue('Spinlock');
end;
procedure TForm5.SpinlockIncValue;
var
i: integer;
value: integer;
begin
for i := 1 to CNumRepeat do
begin
FSpinlock.Enter;
value := FValue;
FValue := value + 1;
FSpinlock.Exit;
end;
end;
procedure TForm5.SpinlockDecValue;
var
i:integer;
value:integer;
begin
for I := 1 to CNumRepeat do
begin
Fspinlock.Enter;
VALUE:=FVALUE;
FVALUE:=VALUE-1;
Fspinlock.Exit;
end;
end;
procedure TForm5.MTwithinterlockedClick(Sender: TObject);//互鎖操作,匯編指令級別
begin
{當共享數據足夠小並且您只需要遞增它或交換兩個值時,可以選擇在不鎖定的情況下執行此操作。所有現代處理器都實現了可以對存儲器位置進行簡單操作的指令,使得另一個處理器不會中斷正在進行的操作。
這些指令有時被稱為互鎖操作,而用它們編程的整個想法被稱為無鎖編程,或者有時稱為微鎖定。后一個術語實際上更合適,因為CPU確實做了一些鎖定。這種鎖定發生在匯編指令級別,因此比基於操作系統的鎖定(如關鍵部分)快得多。
}
StartTimer;
FValue := 0;
RunInParallel(InterlockedIncValue, InterlockedDecValue);
StopTimer;
LogValue('Interlocked');
end;
procedure TForm5.InterlockedIncValue;
var
i: integer;
begin
for i := 1 to CNumRepeat do
TInterlocked.Increment(FValue);
end;
procedure TForm5.InterlockedDecValue;
var
i: integer;
begin
for i := 1 to CNumRepeat do
TInterlocked.Decrement(FValue);
end;
end.
原文地址:https://blog.csdn.net/qq_25439957/article/details/89431389