[转]Delphi多线程编程入门(一)
最近Ken在比较系统地学习Delphi多线程编程方面的知识,在网络上查阅了很多资料。现在Ken将对这些资料进行整理和修改,以便收藏和分享。内容基本上是复制粘贴,拼拼凑凑,再加上一些修改而来。各个素材的来源已经很难搞清楚,因此不再一一说明。一些资料可能有点老,但仍然有参考价值。篇幅比较长,耐心点看完吧。
多线程共存于应用程序中是现代操作系统中的基本特征和重要标志。为了提高程序的运行效率,在操作系统中提出了进程和线程的概念,在一个进程中可以包含多个线程,进程作为资源分配的基本单位,线程作为独立运行和独立调度的基本单位。关于多线程的更详细说明建议粗略地阅读下百度百科《多线程》。现在PC的硬件性能越来越好,多线程能够充分发挥这些性能,让程序的用户体验更好。
多线程的两个概念:
1)进程:也称任务,程序载入内存,并分配资源,称为“一个进程”。
注意:进程本身并不一定要正在执行。进程由以下几部分组成:
a>一个私有的地址空间,它是进程可以使用的一组虚拟内存地址空间;
b>程序的相关代码、数据源;
c>系统资源,比如操作系统同步对象等;
d>至少包含一个线程(主线程);
2)线程:是程序的执行单位(线程本身并不包括程序代码,真正拥有代码的是进程),每个进程至少包括一个线程,称为主线程,一个进程如果有多个线程,就可以共享同一进程的资源,并可以并发执行。
线程是进程的一个执行单元,是操作系统分配CPU 时间的基本实体,线程主要由如下两部分组成:
a>数据结构;
b>CPU 寄存器和堆栈;
一个进程中的线程,可以独立运行,也可以控制另一个线程的运行。
多线程带来如下好处:
1)避免瓶颈;
2)并行操作;
3)提高效率;
在多线程中,通过优先级管理,可以使重要的程序优先操作,提高了任务管理的灵活性。
另一方面,在多CPU 系统中,可以把不同的线程在不同的CPU 中执行,真正做到同时处理多任务(Win 98 只是模拟的,而Win/NT/2000是真正的多CPU同时操作)。
也有潜在的坏处:
1)写得不好更容易出现未知错误;
2)如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换;
3)更多的线程需要更多的内存空间;
4)线程的中止需要考虑其对程序运行的影响。
当然只要熟悉多线程编程,这些坏处都可以尽量避免的。
下面提供一些代码,供大家在尝试中去理解。
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 500000 do
begin
Canvas.TextOut(10, 10, IntToStr(i));
end;
end;
上面程序运行时, 我们的窗体基本是 "死" 的, 可以在你在程序运行期间拖动窗体试试...
Delphi 为我们提供了一个简单的办法(Application.ProcessMessages)来解决这个问题:
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 500000 do
begin
Canvas.TextOut(10, 10, IntToStr(i));
Application.ProcessMessages;
end;
end;
这个 Application.ProcessMessages; 一般用在比较费时的循环中, 它会检查并先处理消息队列中的其他消息.
但这算不上多线程, 譬如: 运行中你拖动窗体, 循环会暂停下来...
在使用多线程以前, 让我们先简单修改一下程序:
function MyFun: Integer;
var
i: Integer;
begin
for i := 0 to 500000 do
begin
Form1.Canvas.Lock;
Form1.Canvas.TextOut(10, 10, IntToStr(i));
Form1.Canvas.Unlock;
end;
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
MyFun;
end;
细数上面程序的变化:
1、首先这还不是多线程的, 也会让窗体假 "死" 一会;
2、把执行代码写在了一个函数里, 但这个函数不属于 TForm1 的方法, 所以使用 Canvas 是必须冠以名称(Form1);
3、既然是个函数, (不管是否必要)都应该有返回值;
4、使用了 500001 次 Lock 和 Unlock.
Canvas.Lock 好比在说: Canvas(绘图表面)正忙着呢, 其他想用 Canvas 的等会;
Canvas.Unlock : 用完了, 解锁!
在 Canvas 中使用 Lock 和 Unlock 是个好习惯, 在不使用多线程的情况下这无所谓, 但保不准哪天程序会扩展为多线程的; 我们现在学习多线程, 当然应该用.
在 Delphi 中使用多线程有两种方法: 调用 API、使用 TThread 类; 使用 API 的代码更简单,但Ken建议用 TThread 类. 以下是使用 API 的代码:
function MyFun(p: Pointer): Integer; stdcall;
var
i: Integer;
begin
for i := 0 to 500000 do
begin
Form1.Canvas.Lock;
Form1.Canvas.TextOut(10, 10, IntToStr(i));
Form1.Canvas.Unlock;
end;
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ID: THandle;
begin
CreateThread(nil, 0, @MyFun, nil, 0, ID);
end;
代码分析:
CreateThread 一个线程后, 算上原来的主线程, 这样程序就有两个线程、是标准的多线程了;
CreateThread 第三个参数是函数指针, 新线程建立后将立即执行该函数, 函数执行完毕, 系统将销毁此线程从而结束多线程的故事.
CreateThread 要使用的函数是系统级别的, 不能是某个类(譬如: TForm1)的方法, 并且有严格的格式(参数、返回值)要求, 不管你暂时是不是需要都必须按格式来;
因为是系统级调用, 还要缀上 stdcall, stdcall 是协调参数顺序的, 虽然这里只有一个参数没有顺序可言, 但这是使用系统函数的惯例.
CreateThread 还需要一个 var 参数来接受新建线程的 ID, 尽管暂时没用, 但这也是格式; 其他参数以后再说吧.
这样一个最简单的多线程程序就出来了, 咱们再用 TThread 类实现一次
type
TMyThread = class(TThread)
protected
procedure Execute; override;
end;
procedure TMyThread.Execute;
var
i: Integer;
begin
FreeOnTerminate := True; {这可以让线程执行完毕后随即释放}
for i := 0 to 500000 do
begin
Form1.Canvas.Lock;
Form1.Canvas.TextOut(10, 10, IntToStr(i));
Form1.Canvas.Unlock;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TMyThread.Create(False);
end;
TThread 类有一个抽象方法(Execute), 因而是个抽象类, 抽象类只能继承使用, 上面是继承为 TMyThread.
继承 TThread 主要就是实现抽象方法 Execute(把我们的代码写在里面), 等我们的 TMyThread 实例化后, 首先就会执行 Execute 方法中的代码.
按常规我们一般这样:
procedure TForm1.Button1Click(Sender: TObject);
var
MyThread: TMyThread;
begin
MyThread := TMyThread.Create(False);
end;
因为 MyThread 变量在这里毫无用处(并且编译器还有提示), 所以不如直接写做 TMyThread.Create(False);
我们还可以轻松解决一个问题, 如果: TMyThread.Create(True) ?
这样线程建立后就不会立即调用 Execute, 可以在需要的时候再用 Resume 方法执行线程, 譬如:
procedure TForm1.Button1Click(Sender: TObject);
var
MyThread: TMyThread;
begin
MyThread := TMyThread.Create(True);
MyThread.Resume;
end;
//可简化为:
procedure TForm1.Button1Click(Sender: TObject);
begin
with TMyThread.Create(True) do Resume;
end;
想进一步了解Delphi多线程编程,请继续看下一篇博文。
[转]Delphi多线程编程入门(一)的更多相关文章
- [转]Delphi多线程编程入门(二)——通过调用API实现多线程
以下是一篇很值得看的关于Delphi多线程编程的文章,内容很全面,建议收藏. 一.入门 ㈠. function CreateThread( lpThreadAttributes: Pointer ...
- 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥) 介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...
- 微博,and java 多线程编程 入门到精通 将cpu 的那个 张振华
http://down.51cto.com/data/2263476 java 多线程编程 入门到精通 将cpu 的那个 张振华 多个用户可以同时用一个 vhost,但是vhost之间是隔离的. ...
- delphi 多线程编程
开始本应该是一篇洋洋洒洒的文字, 不过我还是提倡先做起来, 在尝试中去理解.先试试这个: procedure TForm1.Button1Click(Sender: TObject); var i: ...
- 【转】Delphi多线程编程
文章来源: http://liukun966123.my.gsdn.net/2004/10/22/4797/ Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书 ...
- C++多线程编程入门之经典实例
多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对多线程的理解程度从一个侧面反映了程序员的编程水平. 其实C++语言本身并没有提供多线程机制,但Windows系统 ...
- Windows多线程编程入门
标签(空格分隔): Windows multithread programming 多线程 并发 编程 背景知识 在开始学习多线程编程之前,先来学习下进程和线程 进程 进程是指具有一定独立功能的程序在 ...
- Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间, ...
- Delphi多线程编程--线程同步的方法(事件、互斥、信号、计时器)简介
更详细的可以参考:http://www.cnblogs.com/xumenger/p/4450659.html 或者参考之后的博客 四个系统内核对象(事件.互斥.信号.计时器)都是线程同步的手段,从这 ...
随机推荐
- 【转】深入理解TextView实现Rich Text--在同一个TextView设置不同字体风格
深入理解TextView实现Rich Text--在同一个TextView设置不同字体风格 作者: 字体:[增加 减小] 类型:转载 本篇文章是对Android中在同一个TextView中设置不同 ...
- 配置SQL Server Session方法
以下过程是在Win 2003 SP2 + IIS 6.0, ASP.NET 2.0, SQL Server 2005下进行的. 1. 安装Session数据库到Framework目录 C:\WINDO ...
- Android中的CharSequence和String
String 类代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例来实现. (这个没啥了解的吧,经常用 class)public interface ...
- PHP回调函数的几种用法
PHP回调函数的实现方法 目录 前言 全局函数的回调 类静态函数的回调 对象的方法的回调 PHP事件模型(观察者模式)的实现思路 前言 最近在开发一个PH ...
- saltstack故障解决
[root@saltstack_s ~]# salt '*' test.pingSalt request timed out. The master is not responding. If thi ...
- 根据子查询批量删除的sql语句
delete zi_provider_sa a where a.scheme_id in (select t.Id from zi_provider_scheme t where t.prov_id ...
- 第十篇 Replication:故障排除
本篇文章是SQL Server Replication系列的第十篇,详细内容请参考原文. 复制故障排除是一项艰巨的任务.在任何复制设置中,都涉及到很多移动部件,而可用的工具并不总是很容易识别问题.Th ...
- SWIFT 闭包的简单使用
import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: ...
- curl获得http响应码 302 和绑定host
shell curl 取得HTTP返回的状态 获取状态码 curl -I -m 10 -o /dev/null -s -w %{http_code} www.baidu.com 获取时间 curl ...
- Oracle 12C -- 使用seed PDB创建新的pdb
$ sqlplus '/as sysdba' SQL*Plus: Release Production on Tue Jun :: Copyright (c) , , Oracle. All righ ...