こんにちは、
Delphi 7で作成したアプリをDelphi 2007へ移植しております。
スレッドを作成してシリアルデータ受信を行っていて、メインスレッドでデータ処理を行っています。一つ問題がありまして、ボタン上にマウスをかざす事でヒント表示を行うところで原因不明の動作をします。
メインスレッドをデータ処理用として、データ受信用スレッドを作り動作させているのですが、メイン画面上に複数あるTToolButtonボタンの中で、EnabledプロパティーがFalseとなっているボタンの上にマウスを移動させると、ヒント表示が空白となり、受信スレッドが止まってしまうのです。EnabledプロパティーがTrueとなっているボタンはマウスをかざして問題なくヒント表示が行えスレッドも動作し続けます。メモリ漏れかなと思いましたがそうではないようです。(アプリ終了後に漏れ表示するオプション付けてみました。)
以下スレッド実行部分です。解決につながるヒントを頂けませんでしょうか?
procedure TForm2.Execute;
begin
while not Terminated do
begin
if Form1.CommErr=false then GetData;
Application.ProcessMessages;
sleep(5);
end;
end;
環境は、Vista日本語版SP2、Delphi 2007 (December 2007 Update済)です。
よろしくおねがいします。
とりえあえず
どこがスレッド?
KHE00221様、
説明が足りませんでした。
スレッドはUnit2.pasへ書きました。
メインのフォームUnit1.pasでは、
uses
..., Unit2, ...
type
TForm1 = class(TForm)
..
ToolButton1: TToolButton;
ToolButton2: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
ToolButton6: TToolButton;
...
....
private
Thread1: TFrom2;
TForm1.FormShow()プロシージャで
...
Thread1 := TFrom2.Create(True);
Thread1.Priority := tpLowest;
Thread1.Resume;
でTFrom2を起動しています。Form1の表示と同じタイミングでForm2が動いています。
また、Unit2.pasでは最初の投稿で書いた以外に、
type
TForm2 = class(TThread)
private
....
function GetData: boolean;
....
protected
procedure Execute; override;
public
...
end;
としています。
さらに、ToolButton1をクリックして、
procedure TForm1.ToolButton1Click(Sender: TObject);
begin
if start.Enabled = false then exit;
StartProcess(self);
end;
を行います。
startと書いているのは、dfmで
object ToolButton1: TToolButton
Left = 120
Top = 0
Action = Start
ParentShowHint = False
ShowHint = True
end
として、TActionのOnExecuteイベントを使っている為です。
このボタンのヒントは、
TForm1.FormCreate()プロシージャで
Start.Hint := 'スタート';
としています。
StartProcess()では、
Start.Enabled:=False
として、ボタンを利用不可にしていますが、ここでマウスポインタが上にくると、ヒントが空白になりForm2が止まる(一時停止)する現象が出ます。マウスポインタをボタンから外せば、Form2は再開します。
他のボタン(ToolButton2〜6)でもTActionのOnExecuteイベントを使用しており、EnabledがTrueの場合は、上記現象が出ません。
From2がなぜ一時停止してヒントも空白表示になるのか原因を突き止めていません。
> TForm2 = class(TThread)
スレッドなのにTForm2という名前なのですね
とりあえずその人がApplication.ProcessMessagesするのはおかしい
(ワーカスレッドがメッセージポンプする必要はない、と言うかしてはいけない)ので外してみてください
tor様、
ありがとうございます。
ご指摘のApplication.ProcessMessagesをコメントアウトして試したところ、状況は変わらないようです。
現象を良く見てみたところ、EnabledがFalseとなっているボタン上にマウスポインタを持ってくると、一瞬(0.3秒?)ですが本来表示すべきヒントが表示されるようです。その後は、一瞬見えた文字列は消えてしまい、マウスポインタが上にいる限りは、ヒント表示の枠だけが表示され、Form2スレッドが一時停止している状態です。
tor様、
>> TForm2 = class(TThread)
>スレッドなのにTForm2という名前なのですね
名前が紛らわしいのですが、Unit2.pasでは
type
TForm2 = class(TThread)
private
....
function GetData: boolean;
....
protected
procedure Execute; override;
public
...
end;
以外に、
type
TForm2Thread = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
DatWriteFlag: integer;
DatReadFlag: integer;
...
..
public
end;
を定義しています。
FormCreateでは通信ポートを開けて、FormDestroyではポートを閉じる処理をしています。
もう訳がわからない状態っぽいので、プログラムを整理しなおしては如何ですか?
メインスレッド
フォーム+ボタン (スレッドの開始、停止)
データ処理ルーチン (受信データをCaptionに表示)
データ受信スレッド
データ受信 (受信したらメインフォームにデータを転送)
という最小構成をつくり直してみてください。
スレッドでは行ってはいけない動作というのがありますので
その点を要チェックしてみてください。特にメインフォームのVCLにアクセスしたりしてはいけません。
あとスレッドオブジェクトの生成破棄の管理もポカミスが多い箇所ですので注意が必要です。
データの受信があまりにも多い場合は、そのたびにメインスレッドを呼びだすとメインスレッドの動作は重くなります。とりあえず、メインスレッドに送るデータ頻度は1/100秒以上にしてみてください。ちゃんと処理するには、データ処理部分もスレッド化する必要が出てきます。
ここまで原点に戻れば自ずと問題箇所はみえてくると思います。
恐らくはスレッドの理解が足りないのだと思います。
TForm2Thread = class(TForm)
TForm2 = class(TThread)
名前逆じゃないか・・・
Form2: TForm2 があってどっかで
誤動作してるんじゃないのか?
monaa様、
ありがとうございます。
最小構成で作り直し、、、というか移植し直しを考えます。
Delphi7でビルドしてこの現象は出ていないと言う事なので、
Delphi2007でビルド出来るようになって出たのだと思います。
小出しで申し訳ないのですが、OSが同じXPでも現象が出ないPCもあり、ハードが古めのPCで出る様な気がします。で、実際にビルドしているPC(Vista SP2)では現象が出ません。
メモリ漏れはないと思うのですが、原因はまだ不明です。
KHE00221様、
ありがとうございます。
名前が紛らわしいですが、逆なんです。ワーカスレッド作成でも
Form2: TForm2;
..
..
Form2 := TForm2.Create(True);
と書いてあるところはなく、Unit1.pasで
Thread1: TForm2;
..
..
Thread1 := TForm2.Create(True);
としています。
TForm2スレッドが定義してあるUnit2.pasで、
TForm2Threadフォームも定義してあり、
TForm2スレッドの受信処理で、TForm2Threadフォームの
メソッドやプロパティを使用しています。
monaa様のご指摘の「(ワーカ)スレッドでは行ってはいけない動作...メインフォームのVCLにアクセスしたりしてはいけません」を見て気になりところもあります。
TForm2スレッドの受信処理メソッドでForm1フォームのプロパティを操作したり、同フォームのメソッドを呼んだりしているのですが、これも問題あるかもしれません。
例えば、Form1.CommErr := True;とかForm1.StopProcess;など、、、
名は体を現すと言いますが。
>名前が紛らわしいですが、逆なんです。ワーカスレッド作成でも
紛らわしいことは止めましょう。
Thread1: TForm2; は 女:T男 と書いている様な物です。
スレッドとフォームは別物として処理しましょう。
過去の記事の検索でスレッド,Synchronizeでまず検索をしてみて下さい。
ツイート | ![]() |