Difference between revisions of "Multithreaded Application Tutorial/ja"
m (→SMP Support) |
|||
Line 143: | Line 143: | ||
良いニュースです。この用法でマルチスレッドでアプリケーションとして正しく動作すれば、それはSMPで並列動作が有効になります。 | 良いニュースです。この用法でマルチスレッドでアプリケーションとして正しく動作すれば、それはSMPで並列動作が有効になります。 | ||
− | == | + | == Lazarusでのマルチスレッドのデバッグ == |
− | + | Lazarusでのマルチスレッドのデバッグは、まだ完全に機能しません。もしマルチスレッドアプリケーションをLinuxでデバッグしようとすると、Xサーバーがハングするといった大きな問題に直面するでしょう。 | |
− | + | これはどうやって解決すべきか分かっていませんが、回避策としては、Xのインスタンスを次のように新しく作ります。 | |
− | |||
X :1 & | X :1 & | ||
− | + | これでOpenして、他のデスクトップへスイッチしたとき、(the one you are working with pressing CTRL+ALT+F7), 元のグラフィカルデスクトップへCTRL+ALT+F8で戻ることができます。 | |
+ | (もしこの組み合わせがうまくいかなかったらSlackwareでのCTRL+ALT+F2で) | ||
− | + | もし、これができたら、Xが開始するデスクトップセッションを次のようにして作ります。 | |
gnome-session --display=:1 & | gnome-session --display=:1 & | ||
− | + | そしてLazarusでプロジェクトの run parameters dialogで"Use display"をチェックして、:1を入力します。 | |
− | + | これでアプリケーションは2番目のXサーバーで動作するようになり、最初のXサーバーでデバッグが可能になりました。 | |
− | + | この方法は、FPC2.0とLazarus 0.9.10で、OSはWindowsとLinuxでテストしました。 |
Revision as of 11:28, 16 August 2006
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
日本語 (ja) │
polski (pl) │
português (pt) │
русский (ru) │
slovenčina (sk) │
中文(中国大陆) (zh_CN) │
概要
このページはいかにしてこれからFree PascalとLazarusを使ってマルチスレッドアプリケーションを書いたりデバッグするかということについて書かれています。
マルチスレッドアプリケーションは、2つかそれ以上のスレッドを作成、同時実行して作業を行うものです。
メインスレッドと呼ばれる一つのスレッドがあります。メインスレッドはオペレーティングシステムによって生成され、自分のアプリケーションの始動すると生成されます。 メインスレッドはかならずひとつのスレッドである必要があり、ユーザーインターフェイス、コンポーネントを更新する唯一のスレッドです(そうでないとアプリケーションは暴走します)。
大元の考え方として、アプリケーションは処理をバックグラウンドで行うことができます(二つ目のスレッドの中で)。その間、ユーザーは仕事を続けることができます(メインスレッドを使って)。
ほかのスレッドの使いかたとして頻繁に反応が必要なアプリケーションがあります。例えばあなたがアプリケーションをつくって、ユーザーがボタンを押して、アプリケーションが処理を開始したとします(すごく重たい処理です)。処理の間、スクリーンは凍りつき反応が無くなり、ユーザーはアプリケーションが落ちたと思うでしょう。よくないことです。もし、その重たい処理を2つ目のスレッドの中で実行したらアプリケーションは反応を返し、まるでそんな処理は行っていないかのように振る舞います。スレッドを開始する前にフォームの処理を開始するボタンを使用不可能にしておけば、ユーザーがそれ以上の仕事を要求することを無くすことができ、名案です。
また、サーバアプリケーションを作る際に、大量のクライアントに返答しなければならない場合にも使えます。
TThreadクラス
このサンプルは「examples/multithreading/」にあります。
マルチスレッドアプリケーションはTThreadクラスを使用すると簡単に作成できます。 このクラスは簡単に追加のスレッド(メインスレッドと並列に実行する)を作ることができます。
そのためには通常、Createコンストラクタと、Executeメソッドの二つのメソッドをオーバーライドしなければなりません。
コンストラクタは、あなたが走らせるスレッドを準備する際に使います。あなたは値と変数もしくはプロパティに初期値を納める必要があります。TThreadのオリジナルのコンストラクタはSuspendedというパラメータを必要とします。 SuspendedがTrueの場合、スレッド作成された後、自動的にスレッドは実行されます。 SuspendedがFalseの場合、スレッド作成された後、直ちにスレッドは実行されます。 スレッドがSuspendedで作成されれば、Resumeメソッドが呼ばれた後に実行されます。
FPCのバージョンが2.0.1以降の場合、TThread.CreateはStackSizeという暗黙のパラメータを持っています。 あなたは必要ならば自分の作るスレッドのデフォルトスタックサイズを変更することが可能です。 スレッド内でディープな手続きを呼び出す場合には重宝するでしょう。 あなたがスタックサイズを指定しなければ、OSによる規定のスタックサイズが使用されます。
あなたはオーバーライドされたExecuteメソッド内にスレッドで実行されるコードを書きます。
TThreadクラスはひとつの Terminated : boolean; という重要なプロパティを持っています。
TerminatedがTrueであって、スレッドがループを持っている場合(これは普通です)、ループは終了されます(デフォルトではFalseです)。したがってどんなサイクルもTerminatedがTrueであるかチェックする必要があり、また速やかにExecuteメソッドを終了させることが可能なように、必要なクリーンアップが終わった後にしなければなりません。
ですからTerminatedメソッドではデフォルトではなにもしないことを、覚えておいてください。Executeメソッドにはメソッドがメソッドを終了するためのサポートを必ず実装しなければなりません。
先に説明したように、スレッドは可視コンポーネントになにかを行うべきではありません。なにかをユーザーに示すためにはメインスレッドで行います。 これを行うためにTThreadにはSynchronizeというメソッドがあります。 このメソッド(パラメータなし)により、連動することが可能です。 あなたがSynchronixe(@MyMethod)として、メソッドを呼び出すとき、スレッドの実行は一時停止されます。そしてMyMethodがメインスレッドで行われた後、スレッド実行が再開されます。
他にもTThreadには重要なプロパティがあります。 FreeOnTerminateはこのプロパティがTrueの際、スレッドオブジェクトはスレッドの実行(Executeメソッド)が停止した後に開放されます。そうでないばあいは、アプリケーションは手動でオブジェクトを開放する必要があります。
例:
Type TMyThread = class(TThread) private fStatusText : string; procedure ShowStatus; protected procedure Execute; override; public Constructor Create(Suspended : boolean); end;
constructor TMyThread.Create(CreateSuspended : boolean); begin FreeOnTerminate := True; inherited Create(CreateSuspended); end;
procedure TMyThread.ShowStatus; begin Form1.Caption := fStatusText; end; procedure TMyThread.Execute; var newStatus : string; begin fStatusText := 'Starting...'; Synchronize(@Showstatus); fStatusText := 'Running...'; while (not Terminated) and ([any condition required]) do begin ... [here goes the code of the main thread loop] ... if NewStatus <> fStatusText then begin fStatusText := newStatus; Synchronize(@Showstatus); end; end; end;
アプリケーション側では,
var MyThread : TMyThread; begin MyThread := TMyThread.Create(True); // This way it doesn't start automatically ... [Here the code initialises anything required before the threads starts executing] ... MyThread.Resume; end;
特別に注意すべきこと
Windowsで-Ctスイッチ(スタックチェック)をつかうスレッドには頭の痛い問題があります。 理由は定かではありませんが、もしデフォルトのスタックサイズを使う場合、TTread.Createでスタックのチェックがおそらくトリガーとなって発生します。 現在の運用上の回避策としては -Ctスイッチを使わないことです。これでメインスレッドで例外をひきおこさなくなります。しかし、新しいスレッドをつくったときに発生することがあります。 これは、スレッドが絶対開始できないように思えます。
スレッド生成時に発生するその他の例外や、これをチェックする良いコードです。
MyThread:=TThread.Create(False); if Assigned(MyThread.FatalException) then raise MyThread.FatalException;
このコードはスレッド生成時に発生するどんな例外でも、メインのスレッドでraiseするように確認します。
マルチスレッドアプリケーションで必要なユニット
Windowsでは特に気をつけることはないのですが、LinuxやMaxOSX,FreeBSDでは、かならずプロジェクトのユニット(つまり、プログラムユニット、.lpr)で、cthreadsユニットをusesする必要があります。
Lazarusアプリケーションのコードでは次のようになるでしょう。
program MyMultiThreadedProgram; {$H+} uses {$ifdef unix} cthreads, {$endif} Interfaces, // this includes the LCL widgetset Forms { add your units here },
SMP(対称型マルチプロセッサCPU)のサポート
良いニュースです。この用法でマルチスレッドでアプリケーションとして正しく動作すれば、それはSMPで並列動作が有効になります。
Lazarusでのマルチスレッドのデバッグ
Lazarusでのマルチスレッドのデバッグは、まだ完全に機能しません。もしマルチスレッドアプリケーションをLinuxでデバッグしようとすると、Xサーバーがハングするといった大きな問題に直面するでしょう。
これはどうやって解決すべきか分かっていませんが、回避策としては、Xのインスタンスを次のように新しく作ります。
X :1 &
これでOpenして、他のデスクトップへスイッチしたとき、(the one you are working with pressing CTRL+ALT+F7), 元のグラフィカルデスクトップへCTRL+ALT+F8で戻ることができます。 (もしこの組み合わせがうまくいかなかったらSlackwareでのCTRL+ALT+F2で)
もし、これができたら、Xが開始するデスクトップセッションを次のようにして作ります。
gnome-session --display=:1 &
そしてLazarusでプロジェクトの run parameters dialogで"Use display"をチェックして、:1を入力します。
これでアプリケーションは2番目のXサーバーで動作するようになり、最初のXサーバーでデバッグが可能になりました。
この方法は、FPC2.0とLazarus 0.9.10で、OSはWindowsとLinuxでテストしました。