扩展Delphi的线程同步对象(l转)

作者:于华

  在编写多线程应用程序时,最重要的是控制好线程间的同步资源访问,以保证线程的安全运行。Win 32 API提供了一组同步对象,如:信号灯(Semaphore)、互斥(Mutex)、临界区(CriticalSection)和事件(Event)等,用来解决这个问题。 

  Delphi分别将事件对象和临界区对象封装为Tevent对象和TcritialSection对象,使得这两个对象的使用简单且方便。但是如果在Delphi程序中要使用信号灯或互斥等对象就必须借助于复杂的Win32 API函数,这对那些不熟悉Win32 API函数的编程人员来说很不方便。因此,笔者用Delphi构造了两个类,对信号灯和互斥对象进行了封装(分别为TSemaphore和TMutex),希望对广大Delphi编程人员有所帮助。 

  一、类的构造 
  我们先对Win32 API的信号灯对象和互斥对象进行抽象,构造一个父类THandleObjectEx,然后由这个父类派生出两个子类Tsemphore和Tmutex。 

  类的源代码如下: 

  unit SyncobjsEx; 

  interface 

  uses Windows,Messages,SysUtils,Classes,Syncobjs; 

  type 

   THandleObjectEx = class(THandleObject) 

  // THandleObjectEx为互斥类和信号灯类的父类 

   protected 

   FHandle: THandle; 

   FLastError: Integer; 

   public 

   destructor Destroy; override; 

   procedure Release;override; 

   function WaitFor(Timeout: DWORD): TWaitResult; 

   property LastError:Integer read FLastError; 

   property Handle: THandle read FHandle; 

   end; 

   TMutex = class(THandleObjectEx)//互斥类 

   public 

   constructor Create(MutexAttributes: PSecurityAttributes; InitialOwner: Boolean;const Name:string); 

   procedure Release; override; 

   end; 

   TSemaphore = class(THandleObjectEx) 

  //信号灯类 

  public 

  constructor Create(SemaphoreAttributes: PSecurityAttributes;InitialCount:Integer;MaximumCount: integer; const Name: string); 

  procedure Release(ReleaseCount: Integer=1;PreviousCount:Pointer=nil);overload; 

   end; 

  implementation 

  { THandleObjectEx }//父类的实现 

  destructor THandleObjectEx.Destroy; 

  begin 

   Windows.CloseHandle(FHandle); 

   inherited Destroy; 

  end; 

  procedure THandleObjectEx.Release; 

  begin 

  end; 

  function THandleObjectEx.WaitFor(Timeout: DWORD): TWaitResult; 

  //等待函数,参数为等待时间 

  begin 

  case WaitForSingleObject(Handle, Timeout) of 

  WAIT_ABANDONED: Result := wrAbandoned; 

  //无信号 

  WAIT_OBJECT_0: Result := wrSignaled; 

  //有信号 

  WAIT_TIMEOUT: Result := wrTimeout;//超时 

  WAIT_FAILED://失败 

   begin 

   Result := wrError; 

   FLastError := GetLastError; 

   end; 

   else 

   Result := wrError; 

   end; 

  end; 

  { TSemaphore }//信号灯类的实现 

  constructor TSemaphore.Create(SemaphoreAttributes: PSecurityAttributes; 

   InitialCount, MaximumCount: integer; const Name: string);//信号灯类的构造函数 

  begin 

  FHandle := CreateSemaphore 

  (SemaphoreAttributes,InitialCount, 

  MaximumCount,PChar(Name)); 

  //四个参数分别为:安全属性、初始信号灯计数、最大信号灯计数、信号灯名字 

  end; 

  procedure TSemaphore.Release(ReleaseCount: Integer=1; PreviousCount: Pointer=nil); 

  //信号灯类的Release方法,每执行一次按指定量增加信号灯计数 

  begin 

   Windows.ReleaseSemaphore(FHandle, ReleaseCount, PreviousCount); 

  end; 

  { TMutex }//互斥类的实现 

  constructor TMutex.Create(MutexAttributes: PSecurityAttributes; 

  InitialOwner: Boolean; const Name: string); 

  //互斥类的构造函数 

  begin 

   FHandle := CreateMutex(MutexAttributes, InitialOwner, PChar(Name)); 

  end; 

  procedure TMutex.Release;//互斥类的Release方法,用来释放对互斥对象的所有权 

  begin 

   Windows.ReleaseMutex(FHandle); 

  end; 

  end. 

  二、信号灯对象与互斥对象的使用 
  1. 信号灯对象 

  信号灯对象维持一个从0到指定最大值之间的数。在其计数大于0时是有信号的,而在其计数为0时是无信号的。信号灯对象可用来限制对共享资源进行访问的线程数量,例如应用程序可使用信号灯对象来限制它建立的窗口数量。 

  用类的Create方法来建立信号灯对象,在调用该方法时,可以指定对象的初始计数和最大计数。该方法有四个参数,依次为:安全属性、初始计数、最大计数和对象名字(以便别的进程的线程可打开指定名字的信号灯句柄)。如: 

  Semaphore := TSemaphore.Create(nil,10,10,''); 

  一般把信号灯的初始计数设置成最大值。每次当信号灯有信号并等待函数返回时,信号灯计数就会减1,而通过调用对象的Release方法可按指定量增加信号灯的计数(默认为加1)。计数值越小就表明访问共享资源的程序越多。如:“Semaphore.Release(3, nil);”,其中第一个参数为增加的信号灯数量,第二个参数为执行该方法之前的信号灯数量。信号灯用法举例: 

  if wrSignaled = Semaphore.WaitFor(10000) then//若信号灯是有信号的 

  begin 

   //打开另一个窗口 

  end 

   Semaphore.Release() 

  在线程建立窗口之前,它使用WaitFor函数确定信号灯的当前计数是否允许建立新的窗口,等待时间设为10秒。 

  2. 互斥对象 

  Mutex对象的状态在它不被任何线程拥有时是有信号的,而当它被拥有时则是无信号的。Mutex对象很适合用来协调多个线程对共享资源的互斥访问(mutually exclusive)。例如,有几个线程共享对数据库的访问时,线程可以使用Mutex对象,一次只允许一个线程向数据库写入。 

  用类的Create方法建立Mutex 对象,在建立Mutex 时,可以为对象起个名字,这样其他进程中的线程可以打开指定名字的Mutex对象句柄。例如: 

  Mutex := TMutex.Create(nil, False, ''); 

  在完成对共享资源的访问后,可以调用Release方法来释放Mutex,以便让别的线程能访问共享资源。如果线程终止而不释放Mutex,则认为该Mutex被废弃。 

  互斥对象用法举例如下: 

  if wrSignaled = Mutex.WaitFor(10000) then//若获得互斥对象的拥有权 

   begin 

   try 

   //往数据库写入 

   finally 

  Mutex.Release;//释放对互斥对象的拥有权 

   end; 

   end; 

  上述类代码在Windows 98,Delphi 5.0下调试通过。

转载于:https://www.cnblogs.com/superfather/archive/2009/03/25/1421197.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 前言 第一部分 Delphi编程基础 第1章 Delphi集成开发环境 1 1.1 集成开发环境简介 1 1.2 集成调试器 5 1.3 开发环境的优化 6 1.3.1 自定义工具栏 6 1.3.2 编程环境设置 7 1.3.3 编辑环境设置 8 1.3.4 工程设置 8 1.4 方法与技巧 9 1.4.1 使用代码浏览器 9 1.4.2 使用代码编辑器 9 1.4.3 使用帮助系统 10 1.4.4 设置IDE桌面 11 第2章 对象Pascal语言 12 2.1 学习对象Pascal语言的一个通用 例程 12 2.2 对象Pascal语言基础 14 2.2.1 标识符 14 2.2.2 保留字和指令字 14 2.2.3 注释 15 2.2.4 数据类型 16 2.2.5 运算符 21 2.2.6 语句 24 2.2.7 过程与函数 27 2.3 对象Pascal语言的关键技术 30 2.3.1 对象和类 31 2.3.2 类的封装与继承 31 2.3.3 构造函数和析构函数 32 2.3.4 多态性 35 2.3.5 抽象类 38 2.3.6 运行时类型信息 39 2.3.7 类方法 41 2.3.8 类引用 42 2.3.9 单元文件与工程文件 43 2.4 异常处理 45 2.4.1 raise语句 45 2.4.2 try...except语句 45 2.4.3 try...finally语句 47 2.5 方法与技巧 48 2.5.1 命名规则 48 2.5.2 在编译时自由设置是否获得提示 信息 48 2.5.3 使用代码模板 49 2.5.4 使用动态多维数组 49 2.5.5 定义两个相互包含的类 50 2.5.6 获取和使用命令行参数 51 2.5.7 引用参数传递 51 第二部分 Delphi编程的核心技能 第3章 窗体和组件 53 3.1 窗体和组件 53 3.1.1 窗体 54 3.1.2 组件 56 3.1.3 在窗体中使用组件 57 3.2 文本组件 60 3.3 特殊输入组件 61 3.4 按钮及其分类组件 63 3.5 列表组件 64 3.6 分组组件 67 3.7 信息反馈组件 69 3.8 表格显示组件 70 3.9 图形显示组件 71 3.10 开发MDI应用程序 73 3.11 常用组件的用法 74 3.12 方法与技巧 84 3.12.1 窗体、组件的使用原则 84 3.12.2 使用信息对话框 85 3.12.3 使用组件的Hint属性 88 3.12.4 使用Edit组件的IME属性 89 3.12.5 将系统字体添加到ComboBox 组件中 89 3.12.6 在RichEdit组件中存取文件 90 3.12.7 设置模态对话框的返回值 90 3.12.8 使用事件处理过程中的Sender 参数 91 3.12.9 为控件生成多行提示信息 91 3.12.10 生成非矩形窗口 92 3.12.11 移动无标题栏窗口 94 3.12.12 制作动态字幕 95 3.12.13 在窗体上动态地设置背景 画面 96 3.12.14 Owner和Parent的区别 97 第4章 菜单、工具栏和状态栏 98 4.1 菜单 98 4.1.1 主菜单 99 4.1.2 鼠标右键弹出式菜单 99 4.1.3 使用菜单模板 99 4.2 工具栏 100 4.2.1 ToolBar 100 4.2.2 CoolBar 100 4.2.3 ControlBar 101 4.3 状态栏 101 4.4 方法与技巧 106 4.4.1 动态创建菜单 106 4.4.2 为菜单动态定义快捷键 108 4.4.3 动态改变菜单 108 4.4.4 定制系统菜单 109 4.4.5 制作图形菜单项 110 4.4.6 在状态栏中添加进度条等其他 组件 111 4.4.7 MDI应用程序中的菜单融合 113 4.4.8 制作可随处拖放的工具栏 116 4.4.9 将菜单项移到菜单栏的最右边 117 4.4.10 运行时控件的移动 117 第5章 键盘和鼠标 119 5.1 键盘事件 119 5.2 鼠标事件 120 5.2.1 常用鼠标事件 120 5.2.2 拖曳事件 120 5.3

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值