# <0> はじめに (Delphi コンカレントプログラミング) --- tags: Delphi プログラミング Pascal embarcadero objectpascal created_at: 2021-12-04 updated_at: 2024-05-22 --- # 0. はじめに 一連の記事では Delphi における**コンカレント (並行) プログラミング**を扱います。 | 日本語 | 英語 | 目的 | |:---|:---|:---| | 並行計算 | Concurrent Computing | 応答性の向上 | | 並列計算 | Parallel Computing | スループットの向上 | `並行計算` と `並列計算` は似ている概念ですが、ちょっと意味合いが異なります。 **See also:** - [並行計算 (Wikipedia)](https://ja.wikipedia.org/wiki/%E4%B8%A6%E8%A1%8C%E8%A8%88%E7%AE%97) - [並列計算 (Wikipedia)](https://ja.wikipedia.org/wiki/%E4%B8%A6%E5%88%97%E8%A8%88%E7%AE%97) ## 0.1. 並行処理 並行処理を行うにはいくつかの方法があります。 ### 0.1.1. プロセスとスレッド **プロセス**とは簡単に言えば実行中のプログラムです。プログラムのインスタンスとも言えます。 **スレッド**とはプログラム内の処理の基本単位です。プロセスには必ず一つはスレッドがあり、**メインスレッド** (プライマリスレッド) と呼ばれます。並行処理のために追加されるスレッドは**バックグラウンドスレッド** と呼ばれます。 メインスレッドでないスレッドの事をワーカースレッドと呼ぶ事があるのですが、混乱を避けるため、当記事では次のような意味で使っています。 | スレッド | 呼称 | |:---|:---| | アプリケーションの主スレッド| メインスレッド | | 作成された副スレッド | バックグラウンドスレッド | | バックグラウンドスレッドのうち、
スレッドプールで管理されているスレッド | ワーカースレッド | | 現在実行中のスレッド | カレントスレッド | 以前の Windows (Microsoft) のマルチスレッド関係のドキュメントでは、 | スレッド | 呼称 | |:---|:---| | アプリケーションの主スレッド
(メインスレッド) | プライマリスレッド | | GUI を操作するスレッド
(バックグラウンドスレッド) | GUI スレッド | | GUI を操作しないスレッド
(バックグラウンドスレッド) | ワーカースレッド | このような使われ方になっていたように思うのですが、現在の Microsoft のドキュメントでは `ワーカースレッド` という呼び方はスレッドプール (後述) に対してしか使われていない気がします (または Windows API のドキュメントの中)。 - フォアグラウンドスレッドとバックグラウンドスレッドがある - UI スレッド = メインスレッド、非 UI スレッド = サブスレッド (バックグラウンドスレッド) - バックグラウンドスレッドとは裏で動く終了しないスレッドの事 ...のように、OS や言語、フレームワーク、ライブラリによって言っている事や指しているものが異なる事があるので注意してください。 ### 0.1.2. タイマーによる並行処理 `TTimer` を使えば、疑似的な並行処理を行う事ができます。 **See also:** - [TTimer (VCL) (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/Vcl.ExtCtrls.TTimer) - [TTimer (FireMonkey) (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/Vcl.ExtCtrls.TTimer) ### 0.1.3. マルチプロセスによる並行処理 別プログラム (常駐プログラム等) を作ってプロセス間通信を行えば**マルチプロセス**による並行処理を行う事ができます。各プロセスのスレッドは別のメモリ空間で実行されるため、データ共有の仕組を考える必要があります。 古い Delphi の `$(DELPHI)\DEMOS\Ipcdemos` にはプロセス間通信のデモプログラムがあります。 ![image.png](./images/81b06ff2-7ff1-3bda-48e9-4640c18820be.png) クライアントプログラム上でのマウス操作をモニタプログラムで監視するものです。また、このサンプルでは RTL に先駆けて同期オブジェクト (`TEvent` / `TMutex`) も実装されていました。 ### 0.1.4. マルチスレッドによる並行処理 **マルチスレッド**を使えば並行処理を行う事ができます。スレッドは同じメモリ空間で実行されるので、データ共有が比較的簡単に行えます。 並行処理としてマルチプロセスがあまり使われないのは、プロセス間通信のコストが高いからです。そもそもマルチスレッドは**ライトウエイトプロセス (Light-weight process)** から出発しています。 この一連の記事では主にマルチスレッドを扱います。 ## 0.2. Delphi とスレッド処理 Delphi にスレッドルーチンやクラスが初めて実装されたのは **Delphi 2** です。Delphi 1 は Windows 3.1 をターゲットとしていたため、スレッド管理ルーチンやクラスは存在しませんでした。 ### 0.2.1 BeginThread / EndThread Delphi には `BeginThread()` と `EndThread()` というスレッドルーチンがあります。初期のものは Windows API をごく薄くラップしたルーチンでした。 | Delphi | Windows API | |:---|:---| | [System.BeginThread()](https://docwiki.embarcadero.com/Libraries/ja/System.BeginThread) | [CreateThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread) | | [System.EndThread()](https://docwiki.embarcadero.com/Libraries/ja/System.EndThread) | [ExitThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitthread) | Delphi 2 での定義は次のようになっています。 ```pascal:system.pas function BeginThread(SecurityAttributes: Pointer; StackSize: Integer; ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: Integer; var ThreadId: Integer): Integer; procedure EndThread(ExitCode: Integer); ``` `BeginThread()` と `EndThread()` は スレッド API を Delphi から安全に使うためのラッパールーチンであり、`CreateThread()` / `ExitThread()` を直接扱う事は推奨されていません。しかしながら、この 2 つのルーチンだけではスレッド処理を行う事はできず、結局は Windows API を併用しなければなりません。 | Delphi | Windows API | |:---|:---| || [CloseHandle()](https://docs.microsoft.com/ja-jp/windows/win32/api/handleapi/nf-handleapi-closehandle) | | | [GetThreadPriority()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadpriority) | | | [ResumeThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread) | | | [SetThreadPriority()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadpriority) | | [System.SysUtils.Sleep()](https://docwiki.embarcadero.com/Libraries/Alexandria/ja/System.SysUtils.Sleep)| [Sleep()](https://docs.microsoft.com/ja-jp/windows/win32/api/synchapi/nf-synchapi-sleep)| | | [SuspendThread()](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread) | || [TerminateThread()](https://docs.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread) | ||[WaitForMultipleObjects()](https://docs.microsoft.com/ja-jp/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects)| ||[WaitForSingleObject()](https://docs.microsoft.com/ja-jp/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject)| 最近の Delphi には Windows プラットフォーム以外で動作する `BeginThread()` / `EndThread()` が用意されています。 ```pascal:system.pas {$IFDEF POSIX} function BeginThread(Attribute: PThreadAttr; ThreadFunc: TThreadFunc; Parameter: Pointer; var ThreadId: TThreadID): Integer; {$ENDIF} ``` Windows 用とパラメータが異なるため、`BeginThread()` と `EndThread()` ですらも、直接扱わない方がいいかと思います。 ### 0.2.2 スレッド操作 スレッド操作を行うクラスについては次の記事以降で紹介します。 # 参考 - [マルチスレッド アプリケーションの作成 (DocWiki)](https://docwiki.embarcadero.com/RADStudio/ja/%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89_%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90%EF%BC%9A%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9) - [マルチスレッド アプリケーションの作成方法 (DocWiki)](https://docwiki.embarcadero.com/RADStudio/ja/%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89_%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90%E6%96%B9%E6%B3%95) - [Delphi 10.2 Tokyo でのスレッド変更 (Qiita: @pik)](https://qiita.com/pik/items/5a913fe5a0712db19890) # 索引 [ [↑ 目次へ](https://qiita.com/items/e8c1ff3a4c74e4c2a4f3) ] [ [→ 1. スレッドオブジェクト](./39da99a10202589e002c.md) ]