我做了一个多窗体多线程通讯程序,主线程用Mscomm定时收数据,一线程实现动态绘图(不止一条线),一线程用Socket实现局域网通讯。由窗体的OnCreate事件启动定时收数据,同时创建绘图线程,因为数据接收频率高,绘图不需要那么高频率,所以想到用定时器来定时唤醒绘图线程,为防止绘图线程一直运行(我试过),一次画完后我把绘图线程挂起,可是这样一来绘图线程根本不执行。
各位帮我看看,该怎么改,(老板一定要用多线程做)
相关代码如下:
procedure TForm_show.FormCreate(Sender: TObject); //窗体产生
begin
.
.
Thread_Wen:=TDrawThread.Create(DrawGrid1,clRed,tpnormal,X1,Y1,X2,Y2);
end;procedure TForm_show.Timer_WenThrTimer(Sender: TObject); {温度线程启动}
begin
if ThrStart_Wen=1 then
begin
F_Wen:=StrToFloat(Edit_Wen.Text);
X1:=X2_Wen;
Y1:=Y2_Wen;
X2:=X1+Step_Wen;
Y2:=Y0-Round(scale_Wen*F_Wen);
X2_Wen:=X2;
Y2_Wen:=Y2;
Thread_Wen.Resume;
Thread_Wen.Suspend;
end;
else
Thread_Wen.Terminate;
end;
unit DrThread;interfaceuses
Classes,Graphics,Grids;type
TDrawThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure Draw;
public
FColor:TColor;
FP:TThreadPriority;
X1s,Y1s,X2s,Y2s:integer;
FDrawGrid:TDrawGrid;
Constructor Create(DrawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
end;implementation
uses show;Constructor TDrawThread.Create(drawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
begin
FDrawGrid:=DrawGr;
FColor:=Col;
X1:=X1s;
Y1:=Y1s;
X2:=X2s;
Y2:=Y2s;
fp:=p;
inherited Create(true);
Priority:=fp;
end;procedure TDrawThread.Draw;
begin
with FDrawGrid.canvas do
begin
lock;
Pen.Color:=FColor;
MoveTo(X1,Y1);
LineTo(X2,Y2);
unlock;
end;
end;procedure TDrawThread.Execute;
begin
synchronize(draw);
freeonterminate:=true;
end;end.
各位帮我看看,该怎么改,(老板一定要用多线程做)
相关代码如下:
procedure TForm_show.FormCreate(Sender: TObject); //窗体产生
begin
.
.
Thread_Wen:=TDrawThread.Create(DrawGrid1,clRed,tpnormal,X1,Y1,X2,Y2);
end;procedure TForm_show.Timer_WenThrTimer(Sender: TObject); {温度线程启动}
begin
if ThrStart_Wen=1 then
begin
F_Wen:=StrToFloat(Edit_Wen.Text);
X1:=X2_Wen;
Y1:=Y2_Wen;
X2:=X1+Step_Wen;
Y2:=Y0-Round(scale_Wen*F_Wen);
X2_Wen:=X2;
Y2_Wen:=Y2;
Thread_Wen.Resume;
Thread_Wen.Suspend;
end;
else
Thread_Wen.Terminate;
end;
unit DrThread;interfaceuses
Classes,Graphics,Grids;type
TDrawThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure Draw;
public
FColor:TColor;
FP:TThreadPriority;
X1s,Y1s,X2s,Y2s:integer;
FDrawGrid:TDrawGrid;
Constructor Create(DrawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
end;implementation
uses show;Constructor TDrawThread.Create(drawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
begin
FDrawGrid:=DrawGr;
FColor:=Col;
X1:=X1s;
Y1:=Y1s;
X2:=X2s;
Y2:=Y2s;
fp:=p;
inherited Create(true);
Priority:=fp;
end;procedure TDrawThread.Draw;
begin
with FDrawGrid.canvas do
begin
lock;
Pen.Color:=FColor;
MoveTo(X1,Y1);
LineTo(X2,Y2);
unlock;
end;
end;procedure TDrawThread.Execute;
begin
synchronize(draw);
freeonterminate:=true;
end;end.
解决方案 »
- (急)窗体最小化问题
- DCOM错误:"拒绝访问!"
- 帮我看看'Select * from mail Where Muser...错在哪啊?
- 如何给自己一个恰当的定位。
- QrExpr表达式求解,小弟向各位高手请教
- InstallShield 5.5 Professional Edition
- 紧急请教:我在win2k server 下写的程序在win98下不能用!! 救命啊
- 求高人指点 Service 服务程序调用外部exe能正常执行的代码!
- 向各位大哥请教一个问题。Delphi5.0的例子csdemo每次运行都说数据库的username、password错误之类的提示,
- 暂别,送分。
- 请介绍学习C/S结构的书!
- ADOStoredProc的問題,幫幫忙!
你都把绘图线程杀死了freeonterminate:=true;
请大家去 http://www.new7wonders.com/c/voting.php 投长城一票
建议:
窗体中创建线程,在窗体Destroy方法中释放线程,每次定时器触发调用
Thread_Wen.Resume;
线程中Execute方法改为
while not terminated do
begin
...
suspend;
end;
按您建议试了,仍然是绘图线程一直运行,一直在画,线程挂不起来。
而且多曲线绘制时,根本不行,线是乱的。
你开了多少个线程在画?
把定时器那部分代码去掉。只留一个线程画就是了。
另外,如果觉得线程suspend再唤醒有些慢, 可以改用TEvent来等待。思路理清,问题可以一个个处理好的。
把定时器那部分代码去掉,那定时绘图线程在哪儿唤醒呢?
begin
//这里要进入循环,不进循环,在Form中控制线程的Resume, Suspend都是假的
while not Terminated do
synchronize(draw);
freeonterminate:=true;
end;
这段我使用过,在OnTimer里Resume线程,只执行一次。
to fsb2001(涵秋) :
恐怕不行,收数据频率较绘图频率高得多,
比较好的做法是用两个线程,一个测数据,写入一个数据缓冲区,用另一个线程来画线,两个线程用同一个缓冲区的数据,通过线程来保证来数据的完整。
这是一个明显的双线程同步的问题。很多相关的书都有介绍。
senliu(翠儿),把关于Timer部分的代码全部统统去掉,既然用了线程,就不要用Timer来凑热闹。zyc(zir) 写的话仔细看看, 希望能让你快速找到错误所在。
根据各位意见,我重做了,在窗体创建中创建线程,主线程收数据写入文本(以前做的),去掉Timer,新添变量P,用于统计收到数据个数,每收5组数据唤醒绘图线
程画一次图,试了还是不行,根本不画。代码如下:
procedure TForm_show.FormCreate(Sender: TObject); //窗体产生
begin
.
.
Thread_Wen:=TDrawThread.Create(DrawGrid1,clRed,tpnormal,X1,Y1,X2,Y2);
end;procedure TForm_show.Timer_StartTimer(Sender: TObject); {发送地址}
begin
if k<=I then
begin
Mscomm1.output:=inttostr(MyAddress[k]);
k:=k+1;
end
else
begin
k:=1;
Mscomm1.output:=inttostr(MyAddress[k]);
k:=k+1;
end;
p:=P+1;
end;procedure TForm_show.MSComm1Comm(Sender: TObject); {收数据}
var
InputString:string;
begin
Inputstring:=Mscomm1.Input;
if k=2 then
begin
Writeln(MyTextFile,DateToStr(time)); //
Writeln(MyTextFile,InputString);
end
else
Writeln(MyTextFile,InputString);
case MyAddress[k-1] of
1: begin
edit_Time.text:=timetostr(time); //在窗体编辑框显示时间和数据
edit_Wen.Text:=inputstring;
if p=5*I then //每收5组数据画一次图
begin
X1:=X2_Wen;
Y1:=Y2_Wen;
F_Wen:=StrToFloat(inputstring);
X2:=X1+Step_Wen;
Y2:=Y0-Round(scale_Wen*F_Wen);
X2_Wen:=X2;
Y2_Wen:=Y2;
Thread_Wen.Resume; //唤醒绘图线程
p:=1;
end;
end;
2:edit_Ye.text:=inputstring;
3:edit_Jing.text:=inputstring;
4:edit_Chu.text:=inputstring;
end;
end;
unit DrThread;interfaceuses
Classes,Graphics,Grids;type
TDrawThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure Draw;
public
FColor:TColor;
FP:TThreadPriority;
X1s,Y1s,X2s,Y2s:integer;
FDrawGrid:TDrawGrid;
Constructor Create(DrawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
end;implementation
uses show;{ TDrawThread }
Constructor TDrawThread.Create(drawGr:TDrawGrid;Col:TColor;P:TThreadPriority;X1s,Y1s,X2s,Y2s:integer);
begin
FDrawGrid:=DrawGr;
FColor:=Col;
X1:=X1s;
Y1:=Y1s;
X2:=X2s;
Y2:=Y2s;
fp:=p;
inherited Create(true);
Priority:=fp;
end;procedure TDrawThread.Draw;
begin
with FDrawGrid.canvas do
begin
lock;
Pen.Color:=FColor;
MoveTo(X1,Y1);
LineTo(X2,Y2);
unlock;
end;
end;procedure TDrawThread.Execute;
begin
while not terminated do
begin
synchronize(draw);
suspend;
end;
end;end.
高手们,帮帮我。
两个线程,一个线程A用于监视目录文件变化,
一个线程B用于处理目录文件变化。
当时我的监视目录线程A在运行期无法启动线程B(奇怪的是在IDE调试期是可以
通过的).我想问题的关键是应该在于
监视数据线程在进入接收态时,进入synchronize保护状态了.
这时候 负责画图的线程是无法更新主窗体上的CANVAS
有朋友建议我用Event可以做这样的事情.因为我当时的任务比较简单
用timer(就是你老板禁止用的)办法解决了.如果用Event 事件机制, 在你的监视数据线程内启动一个事件,
用此事件激活画图线程。但是还需要涉及到临界区的处理
比较麻烦.附带说一句: tTimer实际上封装了 wm_timer 消息的处理
wm_timer 发出的频率实际上是由系统中断int1c决定的.
但是因为它是个消息, 所以 wm_timer并不是可靠定时的.
也就是说在系统繁忙时, tTimer工作就不会稳定.Delphi的主窗体是程序的主线程. mscomm组件如果工作在异步方式接收数据
时,应该是单独跑在自己的线程里的(我没有用过mscomm组件,这段理解是想当然)
你改的改程序还没有解决问题,你的主Thread和DrawThread之间的数据之间还不能实现同步。
好的做法是,用个同步量表示数据池中有多少个数据,但对数据池和同步量的读写本用临界区的方法来控制(也可以用PV方法来控制)。这里面,一个数据应该就是一组数据,包括Color、X1、Y1、X2、Y2,数据池的容纳多少组数据可以经过测试。
主线程循环写入数据,只判定数据池中是否可写数据,不要去控制子线程的运行(否则会出错),子线循环等数据池中的数据,如果池中有一组以上的数据,就画线,否就等,不要supend。用supend和resume不能实现线程同步。