zoukankan      html  css  js  c++  java
  • 线程安全队列 采用双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.
  • 相关阅读:
    TimesTen ODBC 链接库差异及相关命令行工具的使用注意事项
    Makefile当中宏定义传递字符串
    WTL 中的常见问题汇总
    WTL 中CComboBoxEx显示不了的问题
    error C2664 转换错误汇总[转]
    LNK1123: 转换到 COFF 期间失败: 文件无效或损坏[汇总]
    python 安装mysql 客户端遇到的问题
    统计查询基本信息
    使用Log4net记录日志(非常重要)
    EntityFramework中使用sql语句
  • 原文地址:https://www.cnblogs.com/jxgxy/p/2085148.html
Copyright © 2011-2022 走看看