delphi 把多个线程的请求阻塞到另一个线程 TElegantThread

本例是把多个线程访问数据库的请求,全部阻塞到一个线程。

这是实际编程中常见的一种问题。

示例源码下载,所需支持单元均在源码中,且附详细说明。

TElegantThread 的父类是 TSimpleThread

unit uElegantThread;

interface

uses
  Classes, SysUtils, uSimpleThread, uSimpleList, uSyncObjs;

type

  PSyncRec = ^TSyncRec;

  TSyncRec = record
    FMethod: TThreadMethod;
    FProcedure: TThreadProcedure;
    FSignal: TSuperEvent;
    Queued: boolean;
    DebugInfo: string;
  end;

  TSyncRecList = Class(TSimpleList<PSyncRec>)
  protected
    procedure FreeItem(Item: PSyncRec); override;
  End;

  TElegantThread = class(TSimpleThread)
  private
    FSyncRecList: TSyncRecList;

    procedure LockList;
    procedure UnlockList;

    procedure Check;
    procedure DoCheck;

  public

    // AAllowedActiveX 允许此线程访问 COM 如:IE ,
    // 当然,获取 Ie 的 IHtmlDocument2 接口,也必须在此线程内执行
    constructor Create(AAllowedActiveX: boolean = false);
    destructor Destroy; override;

    // ADebugInfo 是调用者用来查错用,一般可以写上过程名 如:‘DoSomeThing‘;
    procedure Queue(AMethod: TThreadMethod; ADebugInfo: string = ‘‘); overload;
    procedure Queue(AProcedure: TThreadProcedure; ADebugInfo: string = ‘‘); overload;

    procedure Synchronize(AMethod: TThreadMethod; ADebugInfo: string = ‘‘); overload;
    procedure Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string = ‘‘); overload;

  end;

implementation

{ TSyncRecList }

procedure TSyncRecList.FreeItem(Item: PSyncRec);
begin
  inherited;
  if Assigned(Item.FSignal) then
    Item.FSignal.Free;
  Dispose(Item);
end;

{ TElegantThread }

procedure TElegantThread.Check;
begin
  ExeProcInThread(DoCheck);
end;

constructor TElegantThread.Create(AAllowedActiveX: boolean);
begin
  inherited;
  FSyncRecList := TSyncRecList.Create;
end;

destructor TElegantThread.Destroy;
begin
  WaitThreadStop;
  FSyncRecList.Free;
  inherited;
end;

procedure TElegantThread.DoCheck;
var
  p: PSyncRec;
  sErrMsg: string;
begin

  LockList;
  try
    p := FSyncRecList.PopFirst; // 每次从 List 取出一个过程来执行
  finally
    UnlockList;
  end;

  if Assigned(p) then
  begin

    try

      if Assigned(p.FMethod) then
        p.FMethod // 执行
      else if Assigned(p.FProcedure) then
        p.FProcedure(); // 执行

    except
      on E: Exception do // 错误处理
      begin
        sErrMsg := ‘DebugInfo:‘ + p.DebugInfo + #13#10;
        sErrMsg := sErrMsg + ‘ErrMsg:‘ + E.Message;
        DoOnDebugMsg(sErrMsg);
      end;
    end;

    if not p.Queued then // 如果是阻塞,请设为有信号,调用者即可返回
    begin
      p.FSignal.SetEvent;
    end;

    Dispose(p);
    Check; // 继续下一次 DoCheck,也就是本过程。
    // 父类 TSimpleThread 已特殊处理,不会递归。

  end;

end;

procedure TElegantThread.LockList;
begin
  FSyncRecList.Lock;
end;

procedure TElegantThread.Queue(AMethod: TThreadMethod; ADebugInfo: string);
var
  p: PSyncRec;
begin
  // 此过程为排队执行

  new(p);
  p.FProcedure := nil;
  p.FMethod := AMethod;
  p.Queued := true;

  LockList;
  try
    FSyncRecList.Add(p); // 把要执行的过程加入 List
    Check; // 启动线程
  finally
    UnlockList;
  end;

end;

procedure TElegantThread.Queue(AProcedure: TThreadProcedure; ADebugInfo: string);
var
  p: PSyncRec;
begin
  new(p);
  p.FProcedure := AProcedure;
  p.FMethod := nil;
  p.Queued := true;
  LockList;
  try
    FSyncRecList.Add(p);
    Check;
  finally
    UnlockList;
  end;
end;

procedure TElegantThread.Synchronize(AMethod: TThreadMethod; ADebugInfo: string);
var
  p: PSyncRec;
  o: TSuperEvent;
begin

  // 此过程为阻塞执行,即调用者必须等到此过程被执行完成才能返回

  new(p);

  p.FProcedure := nil;
  p.FMethod := AMethod;
  p.Queued := false;
  p.FSignal := TSuperEvent.Create; // 创建一个信号
  p.FSignal.ResetEvent; // 清除信号
  o := p.FSignal;

  LockList;
  try
    FSyncRecList.Add(p);
    Check;
  finally
    UnlockList;
  end;

  o.WaitFor; // 等待信号出现
  o.Free;

end;

procedure TElegantThread.Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string);
var
  p: PSyncRec;
  o: TSuperEvent;
begin
  new(p);

  p.FProcedure := AProcedure;
  p.FMethod := nil;
  p.Queued := false;
  p.FSignal := TSuperEvent.Create;
  p.FSignal.ResetEvent;
  o := p.FSignal;

  LockList;
  try
    FSyncRecList.Add(p);
    Check;
  finally
    UnlockList;
  end;

  o.WaitFor;
  o.Free;

end;

procedure TElegantThread.UnlockList;
begin
  FSyncRecList.Unlock;
end;

end.

uElegantThread.pas

附:delphi 进阶基础技能说明

http://www.cnblogs.com/lackey/p/4782777.html

时间: 2024-10-10 06:59:57

delphi 把多个线程的请求阻塞到另一个线程 TElegantThread的相关文章

java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?

首先,服务器的实现不止有这两种方式. 先谈谈题主说的这两种服务器模型: 1.收到一个请求就处理,这个时候就不能处理新的请求,这种为阻塞 这个是单线程模型,无法并发,一个请求没处理完服务器就会阻塞,不会处理下一个请求.一般的服务器不会使用这种方式实现. 2.收到一个请求就新开一个线程去处理任务,主线程返回,继续处理下一个任务,这种为非阻塞 首先纠正一个错误,这并不是非阻塞,它也是阻塞的.相对第一个模型来说,它解决了主线程阻塞的问题,有了一定程度的并发量,但是在每个新开的线程中还是阻塞的.如果100

对tomcat来说,每一个进来的请求(request)都需要一个线程,直到该请求结束。

这段时间折腾了哈java web应用的压力测试,部署容器是tomcat 7.期间学到了蛮多散碎的知识点,及时梳理总结,构建良好且易理解的知识架构把它们组织起来,以备忘.对web应用开发者来说,我们很关心应用可同时处理的请求数,以及响应时间.应用本身和它运行在其中的web容器是两个很重要的影响因素.对tomcat来说,每一个进来的请求(request)都需要一个线程,直到该请求结束.如果同时进来的请求多于当前可用的请求处理线程数,额外的线程就会被创建,直到到达配置的最大线程数(maxThreads

python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)

前言 今天小编YOYO请xiaoming和xiaowang吃火锅,吃完火锅的时候会有以下三种场景: 场景一:小编(主)先吃完了,xiaoming(客)和xiaowang(客)还没吃完,这种场景会导致结账的人先走了,剩下两个小伙伴傻眼了... 场景二:小编(主)先吃完了,xiaoming和xiaowang还没吃饱,一起结账走人. 场景三:小编(主)先等xiaoming和xiaowang吃饱了,小编最后结账一起走人. 主线程与子线程 场景一:主线程已经结束了,子线程还在跑 1.我们把thread1.

死磕 java线程系列之自己动手写一个线程池

欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写的线程池如何测试? 简介 线程池是Java并发编程中经常使用到的技术,那么自己如何动手写一个线程池呢?本文彤哥将手把手带你写一个可用的线程池. 属性分析 线程池,顾名思义它首先是一个"池",这个池里面放的是线程,线程是用来执行任务的. 首先,线程池中的线程应该是有类别的,有的是核心线程,有

死磕 java线程系列之自己动手写一个线程池(续)

(手机横屏看源码更方便) 问题 (1)自己动手写的线程池如何支持带返回值的任务呢? (2)如果任务执行的过程中抛出异常了该怎么处理呢? 简介 上一章我们自己动手写了一个线程池,但是它是不支持带返回值的任务的,那么,我们自己能否实现呢?必须可以,今天我们就一起来实现带返回值任务的线程池. 前情回顾 首先,让我们先回顾一下上一章写的线程池: (1)它包含四个要素:核心线程数.最大线程数.任务队列.拒绝策略: (2)它具有执行无返回值任务的能力: (3)它无法处理有返回值的任务: (4)它无法处理任务

python多线程之线程锁二(同一时间一个线程获得2把线程锁)

#coding:utf-8 '''线程锁''' import threading import time num = 0 #全局变量 num2 = 0 def runs():     time.sleep(1)     global num #在函数内部要对全局变量进行更改,需要进行声明     global num2     lock.acquire() #在操作时锁住,防止其他线程在同一时间对num变量进行加1,从而确保数据在同一时间确保只有一个线程对它进行更改,不然造成数据不正确     

初学线程池--1,自己实现一个线程池

自己实现一个简单的线程池 public interface ThreadPool<Job extends Runnable> { // 启动 void execute(Job job); // 关闭 void shutDown(); // 增加线程 void addWorkThread(int num); // 减少线程 void reduceWorkThread(int num) throws Exception; // 正在执行的线程数 int getSize(); } 实现类 publi

关于类加载线程 和主线程是否是一个线程的疑问

看深入理解java虚拟机(第二版)的时候,作者在226页给出了一段代码,说明类加载器的阻塞问题,感觉这段代码和书中给出的结果有偏差,自己验证了下,和书中的代码运行结果不一致. static{ if(true){ System.out.println(Thread.currentThread()+" init deadloop"); while (true){ } } } public static void main(String[] args){ // <------线程不会执

Java线程学习整理--2---加入另一个线程join

1.join简介: 今天刚学的,这里我简单总结一下,join本身就是“加入”的意思,那么在线程中是什么意思呢?是在一个线程的run方法执行过程中,当特殊情况下需要执行一些其他的操作的时候,我们会用到join这个方法. 假设: 在执行A线程的时候,在A的run方法中,创建 了一个新的线程B,并且启动了,那么接下来分为2种情况: (1):B没有调用join方法: 这个时候A线程和B线程其实是处于同一个级别状态的,A.B线程可以说是竞争关系,共同争夺CPU的使用权限. 不存在那个一定在前执行,那个一定