线程安全队列 采用双list实现

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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值