读书人

线程太伤人了!该如何解决

发布时间: 2013-06-25 23:45:42 作者: rapoo

线程,太伤人了!!!!!!
各位大大,我把控制线程启动和挂起的操作写在一个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.


[解决办法]
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;

读书人网 >.NET

热点推荐