Difference between revisions of "Multithreaded Application Tutorial/ja"

From Lazarus wiki
Jump to navigationJump to search
 
Line 41: Line 41:
  
 
This class permits the creation of an additional thread (alongside the main thread) in a simple way.
 
This class permits the creation of an additional thread (alongside the main thread) in a simple way.
 +
 +
通常あなたは、Createコンストラクタと、Executeメソッドの二つのメソッドをオーバーライドしなければなりません。
  
 
Normally you only have to override 2 methods: the Create constructor, and the Execute method.
 
Normally you only have to override 2 methods: the Create constructor, and the Execute method.
 +
 +
コンストラクタは、あなたが走らせるスレッドを準備する際に使います。あなたは値と変数もしくはプロパティに初期値を納める必要があります。TThreadのオリジナルのコンストラクタはSuspendedというパラメータを必要とします。
 +
SuspendedがTrueの場合、スレッド作成された後、自動的にスレッドは実行されます。
 +
SuspendedがFalseの場合、スレッド作成された後、直ちにスレッドは実行されます。
 +
スレッドがSuspendedで作成されれば、Resumeメソッドが呼ばれた後に実行されます。
  
 
In the constructor, you will prepare the thread to run.
 
In the constructor, you will prepare the thread to run.
Line 49: Line 56:
 
If Suspended = False, the thread will start running just after the creation.  
 
If Suspended = False, the thread will start running just after the creation.  
 
If the thread is created suspended, then it will run only after the Resume method is called.
 
If the thread is created suspended, then it will run only after the Resume method is called.
 +
 +
FPCのバージョンが2.0.1以降の場合、TThread.CreateはStackSizeという暗黙のパラメータを持っています。
 +
あなたは必要ならば自分の作るスレッドのデフォルトスタックサイズを変更することが可能です。
 +
スレッド内でディープな手続きを呼び出す場合には重宝するでしょう。
 +
あなたがスタックサイズを指定しなければ、OSによる規定のスタックサイズが使用されます。
  
 
As of FPC version 2.0.1 and later, TThread.Create also has an implicit parameter for Stack Size.
 
As of FPC version 2.0.1 and later, TThread.Create also has an implicit parameter for Stack Size.
 
You can now change the default stack size of each thread you create if you need it.
 
You can now change the default stack size of each thread you create if you need it.
 
Deep procedure call recursions in a thread are a good example. If you don't specify the stack size parameter, a default OS stack size is used.
 
Deep procedure call recursions in a thread are a good example. If you don't specify the stack size parameter, a default OS stack size is used.
 +
 +
あなたはオーバーライドされたExecuteメソッド内にスレッドで実行されるコードを書きます。
  
 
In the overrided Execute method you will write the code that will run on the thread.
 
In the overrided Execute method you will write the code that will run on the thread.
 +
 +
TThreadクラスはひとつの
 +
Terminated : boolean;
 +
という重要なプロパティを持っています。
  
 
The TThread class has one important property:  
 
The TThread class has one important property:  
 
Terminated : boolean;
 
Terminated : boolean;
 +
 +
TerminatedがTrueであって、スレッドがループを持っている場合(これは普通です)、ループは終了されます(デフォルトではFalseです)。したがってどんなサイクルもTerminatedがTrueであるかチェックする必要があり、また速やかにExecuteメソッドを終了させることが可能なように、必要なクリーンアップが終わった後にしなければなりません。
  
 
If the thread has a loop (and this is usual), the loop should be exited when Terminated is true (it is false by default). So in each cycle, it must check if Terminated is True, and if it is, must exit the .Execute method as quickly as possible, after any necessary cleanup.
 
If the thread has a loop (and this is usual), the loop should be exited when Terminated is true (it is false by default). So in each cycle, it must check if Terminated is True, and if it is, must exit the .Execute method as quickly as possible, after any necessary cleanup.
 +
 +
ですからTerminatedメソッドではデフォルトではなにもしないことを、覚えておいてください。Executeメソッドにはメソッドがメソッドを終了するためのサポートを必ず実装しなければなりません。
  
 
So keep in mind that the Terminate method does not do anything by default: the .Execute method must explicitly implement support for it to quit it's job.
 
So keep in mind that the Terminate method does not do anything by default: the .Execute method must explicitly implement support for it to quit it's job.
 +
 +
先に説明したように、スレッドは可視コンポーネントになにかを行うべきではありません。なにかをユーザーに示すためにはメインスレッドで行います。
 +
これを行うためにTThreadにはSynchronizeというメソッドがあります。
 +
このメソッド(パラメータなし)により、連動することが可能です。
 +
あなたがSynchronixe(@MyMethod)として、メソッドを呼び出すとき、スレッドの実行は一時停止されます。そしてMyMethodがメインスレッドで行われた後、スレッド実行が再開されます。
  
 
As we explained earlier, the thread should not interact with the visible components. To show something to the user it must do so in the main thread.  
 
As we explained earlier, the thread should not interact with the visible components. To show something to the user it must do so in the main thread.  
Line 67: Line 94:
 
Synchronize requires a method (that takes no parameters) as an argument.  
 
Synchronize requires a method (that takes no parameters) as an argument.  
 
When you call that method through Synchronize(@MyMethod), the thread execution will be paused, the code of MyMethod will run in the main thread, and then the thread execution will be resumed.
 
When you call that method through Synchronize(@MyMethod), the thread execution will be paused, the code of MyMethod will run in the main thread, and then the thread execution will be resumed.
 +
 +
他にもTThreadには重要なプロパティがあります。
 +
FreeOnTerminateはこのプロパティがTrueの際、スレッドオブジェクトはスレッドの実行(Executeメソッド)が停止した後に開放されます。そうでないばあいは、アプリケーションは手動でオブジェクトを開放する必要があります。
  
 
There is another important property of TThread: FreeOnTerminate. If this property is true, the thread object is automatically freed when the thread execution (.Execute method) stops. Otherwise the application will need to free it manually.
 
There is another important property of TThread: FreeOnTerminate. If this property is true, the thread object is automatically freed when the thread execution (.Execute method) stops. Otherwise the application will need to free it manually.
  
Example:
+
:
  
 
   Type
 
   Type

Revision as of 14:13, 11 April 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を使ってマルチスレッドアプリケーションを書いたりデバッグするかということについて書かれています。

This page will try to explain how to write and debug a multithreaded application with Free Pascal and Lazarus.

マルチスレッドアプリケーションは、2つかそれ以上のスレッドを作成、同時実行して作業を行うものです。

A multithreaded application is one that creates two or more threads of execution that work at the same time.

メインスレッドと呼ばれる一つのスレッドがあります。メインスレッドはオペレーティングシステムによって生成され、自分のアプリケーションの始動すると生成されます。 メインスレッドはかならずひとつのスレッドである必要があり、ユーザーインターフェイス、コンポーネントを更新する唯一のスレッドです(そうでないとアプリケーションは暴走します)。

One of the threads is called the Main Thread. The Main Thread is the one that is created by the Operating System, once our application starts. The Main Thread must be the only thread that updates the components that interfaces with the user (else, the application may hang).

大元の考え方として、アプリケーションは処理をバックグラウンドで行うことができます(二つ目のスレッドの中で)。その間、ユーザーは仕事を続けることができます(メインスレッドを使って)。

The main idea is that the application can do some processing in background (in a second thread) while the user can keep working (using the main thread).

ほかのスレッドの使いかたとして頻繁に反応が必要なアプリケーションがあります。例えばあなたがアプリケーションをつくって、ユーザーがボタンを押して、アプリケーションが処理を開始したとします(すごく重たい処理です)。処理の間、スクリーンは凍りつき反応が無くなり、ユーザーはアプリケーションが落ちたと思うでしょう。よくないことです。もし、その重たい処理を2つ目のスレッドの中で実行したらアプリケーションは反応を返し、まるでそんな処理は行っていないかのように振る舞います。スレッドを開始する前にフォームの処理を開始するボタンを使用不可能にしておけば、ユーザーがそれ以上の仕事を要求することを無くすことができ、名案です。

Another use of threads is just to have a better responding application. If you create an application, and when the user press a button, the application start processing (a big job)... and while processing, the screen stop responding, and gives the user the sensation that the application is dead, that is not so nice. If the big job runs in a second thread, the application keeps responding (almost) as if it were idle. In this case it is a good idea, before starting the thread, to disable the buttons of the form to avoid the user to start more than one thread for the job.

また、サーバアプリケーションを作る際に、大量のクライアントに返答しなければならない場合にも使えます。

Another use, is to create a server application that is able to respond to many clients at the same time.

TThreadクラス

このサンプルは「examples/multithreading/」で見つけることができます。

The following example can be found in the examples/multithreading/ directory.

マルチスレッドアプリケーションを作るときにはTThreadクラスを使用すると簡単です。

To create a multithreaded application, the easiest way is to use the TThread Class.

このクラスは簡単に追加のスレッド(メインスレッドと並列な)を作ることができます。

This class permits the creation of an additional thread (alongside the main thread) in a simple way.

通常あなたは、Createコンストラクタと、Executeメソッドの二つのメソッドをオーバーライドしなければなりません。

Normally you only have to override 2 methods: the Create constructor, and the Execute method.

コンストラクタは、あなたが走らせるスレッドを準備する際に使います。あなたは値と変数もしくはプロパティに初期値を納める必要があります。TThreadのオリジナルのコンストラクタはSuspendedというパラメータを必要とします。 SuspendedがTrueの場合、スレッド作成された後、自動的にスレッドは実行されます。 SuspendedがFalseの場合、スレッド作成された後、直ちにスレッドは実行されます。 スレッドがSuspendedで作成されれば、Resumeメソッドが呼ばれた後に実行されます。

In the constructor, you will prepare the thread to run. You will set the initial values of the variables or properties you need. The original constructor of TThread requires a parameter called Suspended. As guessed, being Suspended = True will prevent the thread to start automatically after the creation. If Suspended = False, the thread will start running just after the creation. If the thread is created suspended, then it will run only after the Resume method is called.

FPCのバージョンが2.0.1以降の場合、TThread.CreateはStackSizeという暗黙のパラメータを持っています。 あなたは必要ならば自分の作るスレッドのデフォルトスタックサイズを変更することが可能です。 スレッド内でディープな手続きを呼び出す場合には重宝するでしょう。 あなたがスタックサイズを指定しなければ、OSによる規定のスタックサイズが使用されます。

As of FPC version 2.0.1 and later, TThread.Create also has an implicit parameter for Stack Size. You can now change the default stack size of each thread you create if you need it. Deep procedure call recursions in a thread are a good example. If you don't specify the stack size parameter, a default OS stack size is used.

あなたはオーバーライドされたExecuteメソッド内にスレッドで実行されるコードを書きます。

In the overrided Execute method you will write the code that will run on the thread.

TThreadクラスはひとつの Terminated : boolean; という重要なプロパティを持っています。

The TThread class has one important property: Terminated : boolean;

TerminatedがTrueであって、スレッドがループを持っている場合(これは普通です)、ループは終了されます(デフォルトではFalseです)。したがってどんなサイクルもTerminatedがTrueであるかチェックする必要があり、また速やかにExecuteメソッドを終了させることが可能なように、必要なクリーンアップが終わった後にしなければなりません。

If the thread has a loop (and this is usual), the loop should be exited when Terminated is true (it is false by default). So in each cycle, it must check if Terminated is True, and if it is, must exit the .Execute method as quickly as possible, after any necessary cleanup.

ですからTerminatedメソッドではデフォルトではなにもしないことを、覚えておいてください。Executeメソッドにはメソッドがメソッドを終了するためのサポートを必ず実装しなければなりません。

So keep in mind that the Terminate method does not do anything by default: the .Execute method must explicitly implement support for it to quit it's job.

先に説明したように、スレッドは可視コンポーネントになにかを行うべきではありません。なにかをユーザーに示すためにはメインスレッドで行います。 これを行うためにTThreadにはSynchronizeというメソッドがあります。 このメソッド(パラメータなし)により、連動することが可能です。 あなたがSynchronixe(@MyMethod)として、メソッドを呼び出すとき、スレッドの実行は一時停止されます。そしてMyMethodがメインスレッドで行われた後、スレッド実行が再開されます。

As we explained earlier, the thread should not interact with the visible components. To show something to the user it must do so in the main thread. To do this, a TThread method called Synchronize exists. Synchronize requires a method (that takes no parameters) as an argument. When you call that method through Synchronize(@MyMethod), the thread execution will be paused, the code of MyMethod will run in the main thread, and then the thread execution will be resumed.

他にもTThreadには重要なプロパティがあります。 FreeOnTerminateはこのプロパティがTrueの際、スレッドオブジェクトはスレッドの実行(Executeメソッド)が停止した後に開放されます。そうでないばあいは、アプリケーションは手動でオブジェクトを開放する必要があります。

There is another important property of TThread: FreeOnTerminate. If this property is true, the thread object is automatically freed when the thread execution (.Execute method) stops. Otherwise the application will need to free it manually.

例:

 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;

On the application,

 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;

Special things to take care of

There is a potential headache in Windows with Threads if you use the -Ct (stack check) switch. For reasons not so clear the stack check will "trigger" on any TThread.Create if you use the default stack size. The only work-around for the moment is to simply not use -Ct switch. Note that it does NOT cause an exception in the main thread, but in the newly created one. This "looks" like if the thread was never started.

A good code to check for this and other exceptions which can occur in thread creation is:


    MyThread:=TThread.Create(False);
    if Assigned(MyThread.FatalException) then
      raise MyThread.FatalException;


This code will asure that any exception which occured during thread creation will be raised in your main thread.

Units needed for multithreaded application

On Windows, you don´t need any special unit for this to work. On Linux, MacOSX and FreeBSD, you need the cthreads unit and it must be the first used unit of the project (the program unit, .lpr)!

So, your Lazarus application code should look like:

 program MyMultiThreadedProgram;
 {$H+}
 uses
 {$ifdef unix}
   cthreads,
 {$endif}
   Interfaces, // this includes the LCL widgetset
   Forms
   { add your units here },

SMP Support

The good news is that if your application works properly multithreaded this way, it is already SMP enabled!

Debuging Multithreaded Applications with Lazarus

The debugging on Lazarus is not fully functional yet. But, if you try to debug a multithreaded application on Linux, you will have one big problem: the X server will hang.

It is unknown how to solve this properly, but a workaround is:

Create a new instance of X with:

 X :1 &

It will open, and when you switch to another desktop (the one you are working with pressing CTRL+ALT+F7), you will be able to go back to the new graphical desktop with CTRL+ALT+F8 (if this combination does not work, try with CTRL+ALT+F2... this one worked on Slackware).

Then you could, if you want, create a desktop session on the X started with:

 gnome-session --display=:1 &

Then, in Lazarus, on the run parameters dialog for the project, check "Use display" and enter :1.

Now the application will run on the seccond X server and you will be able to debug it on the first one.

This was tested with Free Pascal 2.0 and Lazarus 0.9.10 on Windows and Linux.