synchronize函数的使用问题 ( 积分: 100 )

  • 主题发起人 主题发起人 bxp780921
  • 开始时间 开始时间
B

bxp780921

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用synchronize调用了一个线程中的过程后,主界面就什么也不能做,我想在他工作的过程中自少有一个按狃能终止他现成执行,现在只好等他自己执行完,
我创建线程是 aa:=zkthread.Create(false);

我的线程是
unit zk;
interface
uses
Fmakecard_msgDAO01,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls,xtqq;
type
zkthread = class(TThread)
private
Fmakecard_msgDAO01:TFmakecard_msgDAO01;
{ Private declarations }
protected
procedure Execute;
override;
public
procedure zk;
end;

implementation
uses makecard_msg, makecard;
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure zkthread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
}
{ zkthread }

procedure zkthread.Execute;
begin
try
synchronize(zk);
//线程同步
except
Terminate ;
showmessage('线程同步错误');
end;

end;


procedure zkthread.zk;
var
Vaac001,Vaac003,Vaac004,vack020,Vsac100:string;
vFErrCode:string;
a,b,c:integer;
begin
a:=0;
b:=0;
Fmakecard_msg.ProgressBar1.Min :=0;
Fmakecard_msg.ProgressBar1.Max :=Fmakecard_msg.ADS_a.RecordCount;
Fmakecard_msg.ProgressBar1.Position:=0;
Fmakecard_msg.ADS_a.First ;
FreeOnTerminate :=True;
while not Fmakecard_msg.ADS_a.Eofdo
begin
//判断终止标志
if Vzkzdbz=True then
begin
//开始中间层提交
Vaac001:=Fmakecard_msg.ADS_a.FieldByName('AAC001').AsString;
//个人序号
Vaac003:=Fmakecard_msg.ADS_a.FieldByName('aac003').AsString ;
//姓名
//转换性别1为男2为女
if trim(Fmakecard_msg.ADS_a.FieldByName('aac004').AsString)='1' then
begin
Vaac004:='男';
//姓别
end
else
if trim(Fmakecard_msg.ADS_a.FieldByName('aac004').AsString)='2' then
begin
Vaac004:='女';
//姓别
end;
//向服务器发出数据请求
try
Fmakecard_msgDAO01:=TFmakecard_msgDAO01.Create(Nil);
Fmakecard_msgDAO01.Load;
try
with Fmakecard_msgDAO01.Inkc06do
begin
Append;
FieldByName('aac001').AsString :=vaac001;
Post;
end;
except
on E: Exceptiondo
end;
Fmakecard_msgDAO01.SendRequest;
vFErrCode:=Fmakecard_msgDAO01.ErrCode;
if Fmakecard_msgDAO01.Outkc06.RecordCount>0 then
begin
vack020:=Fmakecard_msgDAO01.Outkc06.FieldByName('akc020').AsString ;
end
else
begin
vack020:='没有返回卡号';
end;
finally
FreeAndNil(Fmakecard_msgDAO01);
end;
//判断返回信息,如果OK制卡成功,否制卡失败
if uppercase(Trim(vFErrCode))='OK' then
begin
a:=a+1;
Fmakecard_msg.Label2.Caption :='成功:'+inttostr(a);
//个人编号和卡号储存起来,退出时更新主界面中的信息
vsac100stringList.Add(VAAC001);
vakc020stringList.Add(vack020);
end
else
begin
b:=b+1;
Fmakecard_msg.memo1.Lines.Add('个人序号:'+Vaac001+':'+'姓名:'+ Vaac003 +':'+ Vaac004 +':'+vFErrCode+#13) ;
Fmakecard_msg.Label3.Caption :='失败:'+inttostr(b);
end;
//进度条增加
Fmakecard_msg.ProgressBar1.Position:=Fmakecard_msg.ProgressBar1.Position+1;
Fmakecard_msg.ADS_a.Next;
end;

end;
//关闭按牛打开
Fmakecard_msg.Button1.Enabled :=True;
end;

end.
 
关闭按牛打开
够牛的
 
synchronize只需要在操作界面控件或者全局对象(变量)的时候,才需要使用,其作用是在主线程中完成synchronize调用的函数。楼主的zk方法完全用synchronize调用,这和单线程没任何区别,简直是增加了编写的麻烦还一点优势都体现不出来!哎。
 
我应该如何做
 
像下面这样做,这是我写的一个线程同步的例子,带详尽注释:
unit Unit2;
interface
uses
Classes, StdCtrls, Windows, SysUtils, IdHTTP, IdComponent;
type
{ TWorkThread 是工作线程对象 }
TWorkThread = class(TThread)
private
FCurrentNum: integer;
//从界面上取得域名的行
FCurrentURL: string;
//域名
FResultStr: string;
//结果字符串
function GetAlexaData(Worker: TIdHTTP): string;
//获取Alexa数据
function GetBaiduData(Worker: TIdHTTP): string;
//获取Baidu数据
function GetGoogleData(Worker: TIdHTTP): string;
//获取Google数据
function GetPageRank(Worker: TIdHTTP): string;
//获取PageRank数据
procedure Work;
//工作方法
procedure GetCurrentURL;
//向界面请求域名的同步方法
procedure PutResult;
//将结果输出到界面的同步方法
procedure ProgressIt;
//将进度条向前走1格的同步方法
procedure PrepareWorkHTTPComponent(httpWork: TIdHTTP);
//准备工作用的IdHTTP对象
proceduredo
Work(ASender: TObject;
AWorkMode: TWorkMode;
AWorkCount: Int64);
//IdHTTP的OnWork事件指针,注意,如果你使用的是Indy9或者Delphi自带的Indy,请
//将AWorkCount参数的声明改成Integer
protected
procedure Execute;
override;
public
constructor Create(Num: integer);
end;

implementation
uses Unit1, GlobalConst;
{ TWorkThread }
constructor TWorkThread.Create(Num: integer);
begin
FCurrentNum := Num;
// 传递参数
FreeOnTerminate := True;
// 自动删除
inherited Create(False);
// 直接运行
end;

procedure TWorkThread.Execute;
begin
if not Terminated then
Work;
//如果线程没被外部终止,执行Work
end;

function TWorkThread.GetAlexaData(Worker: TIdHTTP): string;
var
ResponseData: string;
snum: integer;
enum: integer;
begin
Result := '';
try
Worker.Request.Referer := AlexaGettingURL;
//引用页赋值
ResponseData := Worker.Get(Format(AlexaGettingURL, [FCurrentURL]));
//从AlexaGettingURL处获得网页全文(注,是html格式的文本)
except
ResponseData := '';
//如果上面的Get发生错误返回,则让ResponseData为空字符串
end;
if ResponseData <> '' then
//不为空
begin
if (Pos('POPULARITY', ResponseData) > 0) then
//找到Popularity标记
begin
snum := pos('POPULARITY', ResponseData);
//记下标记位置
ResponseData := copy(ResponseData, snum, length(ResponseData) - snum);
//拷贝标记开始到整个数据结尾之间的数据
snum := pos('TEXT', ResponseData);//查找TEXT标记
enum := pos('/>', ResponseData);
//查找/>标记
ResponseData := copy(ResponseData, snum + 6, enum - snum - 7);
//拷贝从Text标记+6开始到/>标记-7之间的字符
Result := 'Alexa=' + ResponseData + '|';
//输出结果
end;
end;
end;

function TWorkThread.GetBaiduData(Worker: TIdHTTP): string;
var
Line: string;
ResponseStr: TStringList;
I, iPos: Integer;
begin
Result := '';
ResponseStr := TStringList.Create;
//生成StringList对象,因为下面的代码将按照一行一行的方式来分析文本
try
try
Worker.Request.Referer := BaiduGettingURL;
//引用页
ResponseStr.Text := Worker.Get(Format(BaiduGettingURL, [FCurrentURL]));
//获取数据
except
ResponseStr.Text := '';
end;
for I := 0 to ResponseStr.Count - 1do
//循环每一行
begin
Line := ResponseStr;
//将ResponseStr行数据赋值给Line变量
if Line <> '' then
begin
iPos := Pos('找到相关网页约', Line);
//查找标记为“找到相关网页约”的位置
if iPos > 0 then
//如果找到
begin
Delete(Line, 1, iPos + Length('找到相关网页约') - 1);
//删除标记之前的字符(包括标记本身)
iPos := Pos('篇', Line);
//找“篇”
if iPos > 0 then
//如果找到
begin
Line := Copy(Line, 1, iPos - 1);
//拷贝第一个字符到“篇”的前一个字符之间的字符
if Line <> '' then
//如果不是空的
begin
Result := 'Baidu=' + Line + '|';
//返回结果
Break;
//停止循环
end;
end;
end;
end;
end;
finally
ResponseStr.Free;
//释放对象
end;
end;

procedure TWorkThread.GetCurrentURL;
var
I: Integer;
C: Char;
begin
FCurrentUrl := frmWebsiteSearch.mmoWebsites.Lines[FCurrentNum];
//从界面的mmoWebSites中取出当前行
for I := 1 to Length(FCurrentURL)do
//枚举每一个字符
begin
C := FCurrentURL;
// 取字符
if not (C in ['a'..'z', 'A'..'Z', '-', '.', '0'..'9']) then
//如果字符不是'a'..'z',...规定的字符的话,则表示有非法字符
begin
FCurrentURL := '';
//清空域名字符串,这样线程将会不扫描直接退出
Break;
//终止循环
end;
end;
end;

function TWorkThread.GetGoogleData(Worker: TIdHTTP): string;
var
Line: string;
ResponseStr: TStringList;
I, iPos: Integer;
begin
Result := '';
ResponseStr := TStringList.Create;
//同上,不再赘述
try
try
Worker.Request.Referer := GoogleGettingURL;
ResponseStr.Text := UTF8Decode(Worker.Get(Format(GoogleGettingURL, [FCurrentURL])));
//由于Google页面返回的数据是UTF8编码的,所以要分析数据之前,必须首先解码,UTF8Decode是解码函数
except
ResponseStr.Text := '';
end;
for I := 0 to ResponseStr.Count - 1do
begin
Line := ResponseStr;
if Line <> '' then
begin
iPos := Pos('上约有', Line);
if iPos > 0 then
begin
Delete(Line, 1, iPos + Length('上约有') - 1);
iPos := Pos('项符合', Line);
if iPos > 0 then
begin
Line := Copy(Line, 1, iPos - 1);
if Line <> '' then
begin
Line := StringReplace(Line, '<b>', '', [rfReplaceAll, rfIgnoreCase]);
Line := StringReplace(Line, '</b>', '', [rfReplaceAll, rfIgnoreCase]);
//由于最后的结果是<b>12,335</b>这样的格式,所以要清除<b>和</b>字符,
//上面两个函数就是做清除的。
Result := 'Google=' + Trim(Line) + '|';
Break;
end;
end;
end;
end;
end;
finally
ResponseStr.Free;
end;
end;

function TWorkThread.GetPageRank(Worker: TIdHTTP): string;
var
Line: string;
ResponseStr: TStringList;
I, iPos: Integer;
begin
Result := '';
ResponseStr := TStringList.Create;
//同上,不再赘述
try
try
Worker.Request.Referer := PageRankGettingURL;
ResponseStr.Text := Worker.Get(Format(PageRankGettingURL, [FCurrentURL]));
except
ResponseStr.Text := '';
end;
for I := 0 to ResponseStr.Count - 1do
begin
Line := ResponseStr;
if Line <> '' then
begin
iPos := Pos('PageRank:', Line);
if iPos > 0 then
begin
Delete(Line, 1, iPos + Length('PageRank:') - 1);
Line := Trim(Copy(Line, 1, Length(Line)));
if Line <> '' then
begin
Result := 'PageRank=' + Line + '|';
Break;
end;
end;
end;
end;
finally
ResponseStr.Free;
end;
end;

procedure TWorkThread.ProgressIt;
begin
frmWebsiteSearch.pbProgress.StepIt;
//进度走一步
end;

procedure TWorkThread.PutResult;
begin
frmWebsiteSearch.ProcessResult(FCurrentURL + '&quot;' + FResultStr + '&quot;');
//按照domain&quot;Alexa=10|Google=100|Baidu=20|PageRank=5|的格式,调用
//ProcessResult方法,该方法会按照适当的方式解析字符串,并填入StringGrid对象
end;

procedure TWorkThread.PrepareWorkHTTPComponent(httpWork: TIdHTTP);
begin
{说明,这里的代码都是在Indy10 Snapshot版本下撰写的,如果你用的
版本不是Indy10 Snapshot版本的话,有些行会无法通过编译。没有关系,
注释这些行即可}
httpWork.ReadTimeout := 30000;
//读取超时设定为8秒
httpWork.ConnectTimeout := 30000;
//连接超时设定为10秒
httpWork.Request.UserAgent := 'Mozilla/4.0 (compatible;
MSIE 7.0;
Windows NT 5.1;
Maxthon;
EmbededWB 14.33 from: http://www.bsalsa.com/ EmbeddedWB 14.52;
Internet Explorer EmbeddedWB 14.52;
.NET CLR 1.1.4322;
.NET CLR 2.0.50727;
InfoPath.2)';
//UserAgent模仿的是Maxthon浏览器的输出格式
httpWork.Request.Accept := '*/*';
//允许所有数据
httpWork.Request.AcceptLanguage := 'zh-cn';
//允许简体中文语言
httpWork.HandleRedirects := True;
//处理自动跳转页面
httpWork.RedirectMaximum := 5;
//最大跳转次数为5次
httpWork.HTTPOptions := [hoKeepOrigProtocol];
//保持原有连接协议
httpWork.OnWork :=do
Work;
//给OnWork指针赋值
end;

procedure TWorkThread.Work;
var
httpWork: TIdHTTP;
begin
Synchronize(GetCurrentURL);
{重要说明,所有线程在运行的时候都是和主线程(和其它线程)并行执行的,
所以如果需要访问VCL对象(主线程中,或者任何全局的)和全局变量,必须要做
同步操作,否则将会出现不可预知的情况发生。线程中的同步很简单,首先建立一个
不带参数的过程,然后用Synchronize函数调用这个过程,即可保证这个过程中的代码
都是在主线程下完成的,不会出现冲突问题。例如上面这句Synchronize(GetCurrentURl)
就是如此}
if FCurrentURL = '' then
Exit;
//如果没有成功获得域名,则退出此过程(线程终止)
httpWork := TIdHTTP.Create(nil);
//创建IdHTTP对象
try
PrepareWorkHTTPComponent(httpWork);
//准备IdHTTP对象
{ FResultStr := FResultStr + GetAlexaData(httpWork);//获取Alexa数据,并添加到FResultStr中。下面雷同
if Terminated then
Exit;
FResultStr := FResultStr + GetBaiduData(httpWork);
if Terminated then
Exit;
}
FResultStr := FResultStr + GetGoogleData(httpWork);
if Terminated then
Exit;
// FResultStr := FResultStr + GetPageRank(httpWork);
Synchronize(ProgressIt);
//进度条走1
Synchronize(PutResult);
//输出结果到界面
finally
httpWork.Free;
end;
end;

procedure TWorkThread.DoWork(ASender: TObject;
AWorkMode: TWorkMode;
AWorkCount: Int64);
begin
if Terminated then
Abort;
//如果线程被请求终止,调用Abort完全停止线程当前的任务
end;

end.
 
我已经自己搞定了,还是谢谢上面几个朋友,我把经验告诉大家,请大家以后不要犯同样的错误,办法就是用完后就释放掉,下次用时在调用,在循环中调用,没循环一次调一次.问题就解决了,分就给zqw0117了,白河愁给一点看贴辛苦了
 
后退
顶部