delphi里面我想用线程调用某个函数(这个函数在某个.pas文件里面写好了),该函数是一个1000次的循环,我想用线程调用100次后该线程被挂起,然后通知下一个函数执行。
现有如下问题:1、我如何创建一个线程
2、线程执行到100次此后(线程还没有执行完)如何通知下一个函数执行
现有如下问题:1、我如何创建一个线程
2、线程执行到100次此后(线程还没有执行完)如何通知下一个函数执行
有多个进 程同时工作,而每一个进程又包含有多个线程。但只有一个处理
器的计算机不可能真正地“ 同时”执行多个线程,而是操作系统把时间分成
若干个时间片,然后把一个个时间片分配给 每一个线程。 ---- 一个执行了的程序就是一个进程,一个进程则至少有一个主线程。一位
高级程序 员,绝不会让自己的程序里面只有一个主线程存在(除非只有很
少的几十行代码),而是尽量 让自己的程序在同一时刻里干更多的事,在
比较大一点的应用中尤其如此,象数据库应用程 序,在统计的时候我还想
做其他事呢!因此,如何有效地利用线程则是每一个程序员都应了 解的。
本文就此简单地谈一下在Delphi 中如何利用线程。 ---- ( 一) 当使用线程时,我们主要有两个任务: ---- (1)创建一个线程。 ---- (2)创建一个能作为线程入口的函数。 ---- Windows API 调用CreateThread 函数来创建一个线程。函数如下: HANDLE CreateThread(LPSECURITY_
ATTRIBUTES lpThreadAttributes,
//线程安全属性地址
DWORD dwStackSize,
//初始化线程堆栈尺寸
LPTHREAD_START_ROUTINE lpStartAddress,
//线程函数所指向的地址
LPVOID lpParameter,
//给线程函数传递的参数
DWORD dwCreationFlags,
//有关线程的标志
LPDWORD lpThreadId
//系统分配给线程的ID
);
---- 第一个参数是安全属性,一般设为nil,使用缺省的安全属性。当我们想此
线程有另外的子进 程时,可改变它的属性。 ---- 第二个参数是线程堆栈尺寸,一般设为0,表示与此应用的堆栈尺寸相
同,即主线程 与创建的线程一样长度的堆栈。并且其长度会根据需要自动
变长。 ---- 第三个参数,也是最重要的一个,是一个指向函数名的指针,但传递时
很简单,只需 在线程函数名前加上@ 就可以了。 ---- 第四个参数是你需要向线程函数传递的参数,一般是一个指向结构的指
针。不需传 递参数时,则这个参数设为nil。 ---- 第五个参数,传入与线程有关的一些标志,如果是CREATE_SUSPENDED, 则创建
一个 挂起的线程,即这个线程本身已创建,它的堆栈也已创建。但这个线
程不会被分配给CPU 时 间,只有当ResumeThread 函数被调用后才能执行;当然,
也可以调用SuspendThread 函数再次 挂起线程。要是标志为0,那么一旦建立线
程,线程函数就被立即调用。一般传为0 即可。 ---- 最后一个参数是系统分配给这个线程的唯一的ID 标志。 ---- 下面这个程序MyThreadPro.pas 介绍了线程如何建立及使用: //Your first test Thread Program.
unit MyThreadPro;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
UsedThread: TButton;
NoUsedThread: TButton;
procedure UsedThreadClick(Sender: TObject);
procedure NoUsedThreadClick(Sender: TObject);
var
Form1: TForm1;
implementation
{$R *.DFM}
//这是线程函数,
它可以放在下面程序的任何地方
function MyThreadFunc(P:pointer):Longint;stdcall;
var
i:integer;
DC:HDC;
S:string;
begin
DC:=GetDC(Form1.Handle);
for i:=0 to 100000 do begin
S:=Inttostr(i);
Textout(DC,10,10,Pchar(S),length(S));
end;
ReleaseDC(Form1.Handle,DC);
end;
procedure TForm1.UsedThreadClick(Sender: TObject);
var
hThread:Thandle;//定义一个句柄
ThreadID:DWord;
begin
//创建线程,同时线程函数被调用
hthread:=CreateThread(nil,0,@MyThreadfunc,nil,0,ThreadID);
if hThread=0 then
messagebox(Handle,'Didn’t Create a Thread',nil,MB_OK);
end;
procedure TForm1.NoUsedThreadClick(Sender: TObject);
begin
MyThreadfunc(nil);
//没有创建线程时,直接调用线程函数
end;
end.
---- 上面这个程序介绍了我们在使 用线程及未使用线程二种情况下,运行该
程序的反应。当点UsedThread 按钮时,则建立一个 线程,这时我们可以在程序
进行计算的同时,改变窗体的尺寸及移动它。当按 下NoUsedThread 按钮时,不
建立线程,我们会发现在程序没有计算完之前根本不能做其它任 何事情!
此程序在基于Windows 95 的Delphi 3 中运行通过。
你的第二个问题好像就是线程同步吧
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;