线程,太伤人了!!!!!!

LoveInCoding 2013-05-01 10:19:12
各位大大,我把控制线程启动和挂起的操作写在一个Timer的Ontimer事件中,在消费时间内启动线程,不在消费时间内则挂起线程,等待下次在消费时间内再Resume,ZQ_Consume_MealRoom 表中有三个分组,通过线程数组创建三个监控线程。
现在的问题来了,第一个和第二个线程Suspend后,第三个线程也不工作了(第三个还是在消费时间内的),等到第一个和第二个Resume后,第三个又可以正常运行了,问题点找不到,太受伤了。
onTimer代码如下 :
procedure Tfrmrealtime.StartTimerTimer(Sender: TObject);
var
QY: TADOQuery;
Code: integer; //用于判断是否在消费时段的变量;
i: Integer;
begin
//RoomCode,Tag 两个一维数组,RoomCode用于保存监控组编号;Tag用于保存启动标识 :Jeff 2013.04.28
i := 0;
QY := TADOQuery.Create(self);
QY.Connection := DMDM.CONN;
with QY do
begin
Close;
SQL.Clear;
SQL.Add(' select RoomCode from ZQ_Consume_MealRoom ');
try
Open;
except
ExecSQL;
end;
while not Eof do
begin
if not SameText(RoomID[i],FieldByName('RoomCode').AsString) then
RoomID[i] := FieldByName('RoomCode').AsString;
Code := DMDM.F_IsMealConsumeTime(FieldByName('RoomCode').AsString, FormatDateTime('hh:nn', Now));
if Code = 0 then
begin
if Tags[i] <> -1 then
begin
Tags[i] := -1;
p_Logs('监控组:[' + FieldByName('RoomCode').AsString + ']不在消费时段,监控结束.', true);
if CheckThreadFreed(RunThread[i])=1 then
begin
RunThread[i].Suspend;//线程挂超 Jeff 2013.04.30
end;
end;
end
else
begin
if Tags[i] <> 1 then
begin
Tags[i] := 1;
Kind[i] := Code;
p_Logs('监控组:[' + FieldByName('RoomCode').AsString + ']启动.', False);
DMDM.OpenConsume(RoomID[i], FormatDateTime('ddddd', Now),Kind[i]);
//给监控对像的成员变量赋值 Jeff 2013.04.30
RoomGroup[i]:=TRoomGroup.Create;
RoomGroup[i].RoomCode := RoomID[i];
RoomGroup[i].TimeStr := FormatDateTime('ddddd', Now);
RoomGroup[i].Code := Kind[i];

RunThread[i].Resume;//线程启动 Jeff 2013.04.30
ToolButton2.Caption := '停止监控';
//sleep(1000);
end;
end;
i := i+1;
//当前时间与当前分组的消费时段进行比对;
Next;
end;
end;
QY.Destroy;
end;



线程代码如下:
unit Define;

interface

uses
Classes,Forms,Controls,Windows,comctrls,stdctrls,EastRiver, EastRiverD,Sysutils,grids,Dialogs;

type

//定义监控组线程对象
TRunThread = class(TThread)
private
protected
procedure RuningRoom; //线程监控分组运行
procedure Runing(RoomGroupID:Integer); //线程监控分组运行
procedure Execute; override;
public
RoomGroupID:Integer;
end;


//定义监控分组对象
TRoomGroup = class
private
protected
public
RoomCode:String; //分组号
TimeStr:String; //监控日期
Code:integer; //当前监控分组的餐别
Procedure Continuerun(RoomGroupID:Integer); //继续运行
end;
var
RoomGroup:array[0..9] of TRoomGroup; //监控分组实例对象
RunThread:array[0..9] of TRunThread; //运行控分组线程实例对象
CS: TRTLCriticalSection;//多线程临界区定义
RealRec:TRealRecordInfo;

implementation

uses realtime, DM, FuncPassWord;

{ TRunThread }

procedure TRunThread.Execute;
begin
while not self.Terminated DO
begin
// Synchronize(RuningRoom);
EnterCriticalSection(CS);
try
RuningRoom;
finally
LeaveCriticalSection(CS);
end;
// sleep(50);
end;
end;

procedure TRunThread.Runing(RoomGroupID:Integer);
begin
RoomGroup[RoomGroupID].Continuerun(RoomGroupID);
// Application.ProcessMessages;
end;

procedure TRunThread.RuningRoom;
begin
Runing(RoomGroupID);
end;

{ TRoomGroup }

procedure TRoomGroup.Continuerun(RoomGroupID:Integer);
var
i: Integer;
CID: integer;
begin
for i:=0 to DMDM.DeviceStrList[RoomGroupID].Count-1 Do
begin
CID := StrToInt('$'+DMDM.DeviceStrList[RoomGroupID].Strings[i]);
frmrealtime.Label5.Caption := '正在等待消费机:[' + DMDM.DeviceStrList[RoomGroupID].Strings[i] + ']最后一次刷卡...';
//frmRealTime.p_Logs('正在等待消费机:[' + DMDM.DeviceStrList[RoomGroupID].Strings[i] + ']最后一次刷卡...', false);
if RealReadRecord(frmRealTime.hPort,CID,@RealRec) then
begin
if RealRec.NoCard then
//frmRealTime.p_Logs('消费机:[' + IntToStr(CID) + ']上没有卡片...', false)
else
begin
if RealRec.Consume <> 0 then
begin
frmRealTime.CurMoney := frmRealTime.CurMoney - RealRec.Consume;
EastRiverD.RealFeedback(frmRealTime.hPort,CID,frmRealTime.CurMoney,-1, 0)
end
else
EastRiverD.RealFeedback(frmRealTime.hPort,CID,frmRealTime.CurMoney,-1, 0);
end;
end;
// else
// frmRealTime.p_Logs('消费机:[' + IntToStr(CID) + ']不在线...', false);
end;



end;



end.
...全文
260 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
LoveInCoding 2013-05-05
  • 打赏
  • 举报
回复
我看到多线程里面有一个WaitableTimer ,是否可以利用这个同步方法,达到3分钟,执行APC回调函数?
LoveInCoding 2013-05-05
  • 打赏
  • 举报
回复
那是否是这样,进入线程的每次执行Execute方法,都会先判断是否达到3分钟,如果是,则执行我的其他代码,如果不是,则继续执行同步方法?这样会不会影响到多线程的执行效率?
feiba7288 2013-05-05
  • 打赏
  • 举报
回复
用个变量来判断时间,定义,dtCheckTime: TDateTime; procedure TRunThread.Execute; begin FStop := False;//这里只是初始化,如果你想线程一创建就是暂停的,那这里设置为True while not self.Terminated DO begin if FStop then Suspend;//移到上面来,如果FStop为True,线程停止在这里 //下面只是简单的写了下,供参考 if now - dtCheckTime > 3/60/24 then//3分钟 begin dosomething; dtCheckTime := Now; end; // Synchronize(RuningRoom); EnterCriticalSection(CS); try RuningRoom; finally LeaveCriticalSection(CS); end; // sleep(50); end; end;
LoveInCoding 2013-05-05
  • 打赏
  • 举报
回复
引用 11 楼 feiba7288 的回复:
procedure TRunThread.Execute; begin FStop := False;//这里只是初始化,如果你想线程一创建就是暂停的,那这里设置为True while not self.Terminated DO begin if FStop then Suspend;//移到上面来,如果FStop为True,线程停止在这里 // Synchronize(RuningRoom); EnterCriticalSection(CS); try RuningRoom; finally LeaveCriticalSection(CS); end; // sleep(50); end; end;
还有个问题请教一下,如果我在这个多线程一直在执行的前提下,如果我每隔三分钟要去执行另外的一个操作,要如何处理???
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
非常感谢,有问题再请教您,恩师!
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
引用 12 楼 zjenfon 的回复:
线程创建的时候我是直接用Create参数来控制的,也就是说,如果我创建的时候是挂起的话,那上面的代码就不需要调整,如果我创建的时候参数为False的话,如果想通过Execute来控制的话,就在初始化的时候FStop := true,然后再把if FStop then Suspend;移到上面来来判断,如果FStop为True,线程停止在这里,是这样吗? //----------监控线程在此处创建 jeff 2013.04.29-------------------- RunThread[iTag]:=TRunThread.Create(true);
对的
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
线程创建的时候我是直接用Create参数来控制的,也就是说,如果我创建的时候是挂起的话,那上面的代码就不需要调整,如果我创建的时候参数为False的话,如果想通过Execute来控制的话,就在初始化的时候FStop := true,然后再把if FStop then Suspend;移到上面来来判断,如果FStop为True,线程停止在这里,是这样吗? //----------监控线程在此处创建 jeff 2013.04.29-------------------- RunThread[iTag]:=TRunThread.Create(true);
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
procedure TRunThread.Execute; begin FStop := False;//这里只是初始化,如果你想线程一创建就是暂停的,那这里设置为True while not self.Terminated DO begin if FStop then Suspend;//移到上面来,如果FStop为True,线程停止在这里 // Synchronize(RuningRoom); EnterCriticalSection(CS); try RuningRoom; finally LeaveCriticalSection(CS); end; // sleep(50); end; end;
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
在Execute里面 一开始已经把FStop变成了False;那后面的if FStop then判断,会起作用吗,这里面的执行顺序我有点混乱,还望大大解释一下整个执行顺序是怎样的
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
引用 6 楼 feiba7288 的回复:
[quote=引用 5 楼 zjenfon 的回复:] [quote=引用 4 楼 feiba7288 的回复:] RunThread的启动和暂停用RunThread[i].Start和RunThread[i].Stop,不要再用RunThread[i].Resume和RunThread[i].Suspend;
非常感谢feiba7288大大,问题解决了!有一个地方不明白的是,方法RuningRoom在循环时,线程一旦被Suspend后,不会退出循环后再挂起吗?为什么会干扰到其他的线程???[/quote] 不会退出,当你调用Suspend,线程执行到哪里就停止在哪里,再次调用Resume时,又从那个停止的地方继续执行。[/quote] 这个明白了,感谢!
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
procedure TRunThread.Execute;
begin
  FStop := False;
//这里面已经把FStop变成了False;那后面的if FStop then判断,会起作用吗,这里面的执行顺序我有点混 乱,还望大大解释一下
  while not self.Terminated DO
    begin
      // Synchronize(RuningRoom);
       EnterCriticalSection(CS);
       try
         RuningRoom;
       finally
       LeaveCriticalSection(CS);
       end;
      // sleep(50);

       if FStop then//上面已经把FStop为false了,这里会执行吗???
         Suspend;
    end;
end;
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
干扰到其他的线程是因为你线程中用了临界值。
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
引用 5 楼 zjenfon 的回复:
[quote=引用 4 楼 feiba7288 的回复:] RunThread的启动和暂停用RunThread[i].Start和RunThread[i].Stop,不要再用RunThread[i].Resume和RunThread[i].Suspend;
非常感谢feiba7288大大,问题解决了!有一个地方不明白的是,方法RuningRoom在循环时,线程一旦被Suspend后,不会退出循环后再挂起吗?为什么会干扰到其他的线程???[/quote] 不会退出,当你调用Suspend,线程执行到哪里就停止在哪里,再次调用Resume时,又从那个停止的地方继续执行。
LoveInCoding 2013-05-02
  • 打赏
  • 举报
回复
引用 4 楼 feiba7288 的回复:
RunThread的启动和暂停用RunThread[i].Start和RunThread[i].Stop,不要再用RunThread[i].Resume和RunThread[i].Suspend;
非常感谢feiba7288大大,问题解决了!有一个地方不明白的是,方法RuningRoom在循环时,线程一旦被Suspend后,不会退出循环后再挂起吗?为什么会干扰到其他的线程???
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
RunThread的启动和暂停用RunThread[i].Start和RunThread[i].Stop,不要再用RunThread[i].Resume和RunThread[i].Suspend;
feiba7288 2013-05-02
  • 打赏
  • 举报
回复
StartTimerTimer事件中的“RunThread[i].Suspend;//线程挂超 Jeff 2013.04.30”要改掉;因为你的RunThread中用到了临界值,每个子线程RunThread[i]执行都会进一次临界值,举个例子,当RunThread[0]取得访问CS的权力时(即调用了EnterCriticalSection(CS)),其他子线程就处于等待访问CS的状态,这个时候假如你调用了RunThread[0].Suspend,RunThread[0]就暂停了,但RunThread[0]还没有执行完RuningRoom;也就不会执行到LeaveCriticalSection(CS),这个时候所有线程都挂起在那,等待访问CS的状态。 你可以这么改: 新建一个变量和两个个方法用于控制线程的停止和启动: TRunThread = class(TThread) private FStop: Boolean; protected procedure RuningRoom; //线程监控分组运行 procedure Runing(RoomGroupID:Integer); //线程监控分组运行 procedure Execute; override; public RoomGroupID:Integer; end; procedure TRunThread.Stop; begin FStop := True; end; procedure TRunThread.Start; begin FStop := False; Resume; end; procedure TRunThread.Execute; begin FStop := False; while not self.Terminated DO begin // Synchronize(RuningRoom); EnterCriticalSection(CS); try RuningRoom; finally LeaveCriticalSection(CS); end; // sleep(50); if FStop then Suspend; end; end;
sololie 2013-05-02
  • 打赏
  • 举报
回复
代码太多看着太费事了,实在不想看,虽然可能看了也不懂 得有能上机调试运行的代码才好找原因,纯撸过
LoveInCoding 2013-05-01
  • 打赏
  • 举报
回复
不会就这么沉了吧,自己顶一下!!!

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧