unit uQueueEx;
interface
uses windows,SysUtils,Classes, uCriticalSection;
type
{线程安全队列
}
TQueueEx = class
private
m_bEventNotify:boolean;
m_nExchangeCount:longint;
m_nNextGetPoint:Longint;
m_nNextGetCount:Longint;
m_nNextPutPoint:Longint;
m_csGet: TCriticalSection;
m_csPut: TCriticalSection;
m_lstGet:TList;
m_lstPut:TList;
//存放节点达到多少才交换 防止频繁交换
m_nMinExchangeCount:longint;
//当前队列对象数量
public
// 最小交换对象数量 单队列初始缓冲节点数
constructor Create(bEventNotify:Boolean=True;nMinExchangeCount:Longint=1;nSingleQueueNode:Longint=200);
destructor Destroy; override;
public
//有对象事件通知
m_hEventQueue: THandle;
//系统停止时 设置 nMinExchangeCount=1 以便处理缓冲中的数量
procedure SetMinExchange(nMinExchangeCount:Longint);
procedure Clear;
//nMinExchangeCount>1 长时间未进行数据处理 可调用此函数
function Exchange: boolean;
function Get(): TObject;
function Put( AObject: TObject): boolean;
function GetCount(): longint;
function InfoText:string;
end;
implementation
constructor TQueueEx.Create(bEventNotify:Boolean=True;nMinExchangeCount:Longint=1;nSingleQueueNode:Longint=200);
begin
inherited create;
m_bEventNotify := bEventNotify;
if m_bEventNotify then
m_hEventQueue := CreateEvent(nil, False, False, nil);//自动复位、无信号状态
m_nExchangeCount:= 0;
m_nNextGetPoint := 0;
m_nNextPutPoint := 0;
m_nNextGetCount := 0;
m_nMinExchangeCount := nMinExchangeCount ; //压入队列最小达到值 交换
m_csGet := TCriticalSection.Create;
m_csPut := TCriticalSection.Create;
m_lstGet := TList.Create;
m_lstPut := TList.Create;
m_lstGet.Count := nSingleQueueNode;
m_lstPut.Count := nSingleQueueNode;
end;
destructor TQueueEx.Destroy;
var
n, i: Integer;
Handles: array of THandle;
begin
Clear;
if m_bEventNotify then
CloseHandle(m_hEventQueue);
m_lstGet.Free;
m_lstPut.Free;
m_csGet.Free;
m_csPut.Free;
inherited;
end;
procedure TQueueEx.SetMinExchange(nMinExchangeCount:Longint);
begin
if nMinExchangeCount=0 then
exit;
m_csPut.Enter;
m_nMinExchangeCount := nMinExchangeCount;
if m_bEventNotify then
begin
//达到交换条件
if (m_nNextPutPoint >= m_nMinExchangeCount) and (m_nNextPutPoint>0) then
SetEvent(m_hEventQueue);//设置为有信号状态
end;
m_csPut.Leave;
end;
function TQueueEx.GetCount:Longint;
begin
m_csGet.Enter;
m_csPut.Enter;
Result:= m_nNextPutPoint+m_nNextGetCount-m_nNextGetPoint;
m_csPut.Leave;
m_csGet.Leave;
end;
procedure TQueueEx.Clear;
begin
m_csGet.Enter;
m_csPut.Enter;
try
dec(m_nNextPutPoint);
while (m_nNextPutPoint >=0) do
begin
TObject(m_lstPut.Items[m_nNextPutPoint]).Free;
Dec(m_nNextPutPoint);
end;
m_nNextPutPoint:=0;
while (m_nNextGetPoint < m_nNextGetCount) do
begin
TObject(m_lstGet.Items[m_nNextGetPoint]).Free;
Inc(m_nNextGetPoint);
end;
finally
m_csPut.Leave;
m_csGet.Leave;
end;
end;
function TQueueEx.Put( AObject: TObject):boolean;
begin
Result := False;
m_csPut.Enter;
try
//获取点小于空节点数
if (m_nNextPutPoint < m_lstPut.Count) then
begin
m_lstPut.Items[m_nNextPutPoint] := AObject;
Inc(m_nNextPutPoint);
Result := True;
end
else//获取点大于空节点数
begin
m_lstPut.Add(AObject);
m_nNextPutPoint := m_lstPut.Count;
Result := True;
end;
if m_bEventNotify then
begin
//达到交换条件
if (m_nNextPutPoint >= m_nMinExchangeCount) and (m_nNextPutPoint>0) then
SetEvent(m_hEventQueue);//设置为有信号状态
end;
finally
m_csPut.Leave;
end;
end;
function TQueueEx.Exchange: boolean;
var
lstTemp:Tlist;
begin
Result := False;
//进入取队列临界
m_csGet.Enter;
try
if (m_nNextGetPoint >= m_nNextGetCount) then
begin
//进入存入队列临界
m_csPut.Enter;
try
//满足交换队列条件
if (m_nNextPutPoint>0) then
begin
//交换队列
lstTemp := m_lstGet;
m_lstGet := m_lstPut;
m_lstPut := lstTemp;
m_nNextGetCount:=m_nNextPutPoint;
//设置取放队列获取点
m_nNextPutPoint := 0;
m_nNextGetPoint := 0;
if m_bEventNotify then
SetEvent(m_hEventQueue);//设置为有信号状态
Result := True;
end;
finally
m_csPut.Leave;
end;
end;
finally
m_csGet.Leave;
end;
end;
function TQueueEx.Get(): TObject;
var
lstTemp:Tlist;
begin
Result:=nil;
//进入取队列临界
m_csGet.Enter;
try
if (m_nNextGetPoint < m_nNextGetCount) then
begin
Result := m_lstGet.Items[m_nNextGetPoint];
Inc(m_nNextGetPoint);
end
else
begin
//进入存入队列临界
m_csPut.Enter;
try
//满足交换队列条件
if (m_nNextPutPoint >= m_nMinExchangeCount) and (m_nNextPutPoint>0) then
begin
//交换队列
lstTemp := m_lstGet;
m_lstGet := m_lstPut;
m_lstPut := lstTemp;
m_nNextGetCount:=m_nNextPutPoint;
//设置取放队列获取点
m_nNextPutPoint := 0;
m_nNextGetPoint := 0;
Inc(m_nExchangeCount);
end;
finally
m_csPut.Leave;
end;
if (m_nNextGetPoint < m_nNextGetCount) then
begin
Result:=m_lstGet.Items[m_nNextGetPoint];
Inc(m_nNextGetPoint);
end
end;
if m_bEventNotify then
begin
if (m_nNextGetPoint < m_nNextGetCount) then
SetEvent(m_hEventQueue);//设置为有信号状态
end;
finally
m_csGet.Leave;
end;
end;
function TQueueEx.InfoText: string;
begin
Result := Format(
'交换次数=%6d, 总数量=%6d, 队列最小交换数量=%6d, 压入队列获取点=%6d,压入队列总数量=%6d,'
+'取出获取点=%6d, 取出队列总数量=%6d'#13#10,
[m_nExchangeCount,getCount,m_nMinExchangeCount, m_nNextPutPoint,m_lstPut.Count,
m_nNextGetPoint,m_lstGet.Count]);
end;
{
一、有序资源分配法
二、银行算法
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁
使用多个锁定时,通过确保所有线程都按相同的顺序获取锁定来避免死锁;
}
end.