C 言語を使用した Oracle Tuxedo アプリケーションのプログラミング

     前  次    新しいウィンドウで目次を開く     
ここから内容の開始

マルチスレッドおよびマルチコンテキスト アプリケーションのプログラミング

ここでは、以下の内容について説明します。

 


マルチスレッドおよびマルチコンテキスト アプリケーションのプログラミングに対するサポート

Oracle Tuxedo システムでは、次のアプリケーションがサポートされています。

お使いのオペレーティング システムで POSIX スレッド関数と共にほかのスレッド関数がサポートされている場合は、POSIX スレッド関数を使用することをお勧めします。この関数を使用すると、後でコードをほかのプラットフォームに簡単に移植できます。

お使いのプラットフォームでカーネルレベルのスレッド パッケージ、C 言語の関数、または POSIX 関数がサポートされているかどうかを確認するには、『Oracle Tuxedo システムのインストール』の「Oracle Tuxedo 10g リリース 3 (10.3) プラットフォーム データ シート」で、使用しているオペレーティング システムのデータ シートを参照してください。

マルチスレッドおよびマルチコンテキスト アプリケーションに関するプラットフォーム固有の検討事項

多くのプラットフォームには、マルチスレッドおよびマルチコンテキスト アプリケーション固有の要件があります。プラットフォーム固有の要件については、『Oracle Tuxedo システムのインストール』の「Oracle Tuxedo 10g リリース 3 (10.3) プラットフォーム データ シート」に説明があります。お使いのプラットフォームの要件については、該当するデータシートを参照してください。

関連項目

 


マルチスレッドおよびマルチコンテキスト アプリケーションの計画と設計

ここでは、以下の内容について説明します。

マルチスレッドおよびマルチコンテキストとは

Oracle Tuxedo システムでは、単一のプロセスで複数のタスクを同時に実行できます。このようなプロセスを実装するプログラミング手法はマルチスレッドおよびマルチコンテキストと呼ばれます。この節では、これらの手法に関する基本事項について説明します。

マルチスレッドとは

マルチスレッドとは、1 つのプロセスに複数の実行単位が含まれている処理方法です。マルチスレッド アプリケーションでは、同じプロセスから同時に複数の呼び出しを行うことができます。たとえば、個々のプロセスが 1 つの未終了の tpcall() に制限されることはありません。

サーバのマルチスレッドでは、アプリケーション生成のスレッドがシングルコンテキスト サーバで使用される場合を除き、マルチコンテキストが必要です。マルチスレッドのシングルコンテキスト アプリケーションを作成する唯一の方法は、アプリケーション生成のスレッドを使用することです。

Oracle Tuxedo システムでは、C 言語で記述されたマルチスレッド アプリケーションがサポートされています。COBOL 言語のマルチスレッド アプリケーションはサポートされていません。

次の図は、マルチスレッド クライアントが 3 つのサーバに対して同時に呼び出しを行う方法を示しています。

図 10-1 マルチスレッド プロセスの例

マルチスレッド プロセスの例

マルチスレッド アプリケーションでは、同じサーバで複数のサービス ディスパッチ スレッドを使用できるので、アプリケーションに対して起動するサーバ数が少なくて済みます。

次の図は、異なるクライアントに対して、サーバ プロセスが同時に複数のスレッドをディスパッチする方法を示しています。

図 10-2 1 つのサーバ プロセスによる複数のサービス スレッドのディスパッチ

1 つのサーバ プロセスによる複数のサービス スレッドのディスパッチ

マルチコンテキストとは

コンテキストはドメインへの対応付けです。マルチコンテキストを使用すると、1 つのプロセスで次のいずれかが可能になります。

マルチコンテキストは、クライアントとサーバの両方で使用できます。サーバでマルチコンテキストを使用すると、マルチスレッドも使用することになります。

コンテキストの特徴の詳細については、次のいずれかの節で「コンテキストの属性」を参照してください。

Oracle Tuxedo システムでは、C 言語または COBOL 言語のいずれかで記述されたマルチコンテキスト アプリケーションがサポートされています。ただし、サポートされるマルチスレッド アプリケーションは、C 言語で記述されたものだけです。

次の図は、ドメイン内でのマルチコンテキスト クライアント プロセスの動作を示しています。矢印はサーバへの未終了の呼び出しを表します。

図 10-3 2 つのドメイン内でのマルチコンテキスト プロセス

2 つのドメイン内でのマルチコンテキスト プロセス

マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションの監査

各コンテキストは 1 人のユーザとしてカウントされます。以下に例を示します。

関連項目

マルチスレッドおよびマルチコンテキスト アプリケーションの利点と問題点

マルチスレッドとマルチコンテキストを適切な状況で使用すると、Oracle Tuxedo アプリケーションのパフォーマンスを向上できます。ただし、これらの手法を取り入れる前に、潜在的な利点と問題点について理解しておくことが大切です。

マルチスレッドおよびマルチコンテキスト アプリケーションの利点

マルチスレッドおよびマルチコンテキスト アプリケーションには、以下の利点があります。

アプリケーションで、クライアント スレッドが Microsoft Internet Information Server API または Netscape Enterprise Server インタフェース (NSAPI) によって生成される場合、これらのツールの機能を最大限に利用するにはマルチスレッドが不可欠です。ほかのツールについても同じことが言えます。

マルチスレッドおよびマルチコンテキスト アプリケーションの問題点

マルチスレッドおよびマルチコンテキスト アプリケーションには、以下の問題点があります。

関連項目

クライアントでのマルチスレッドとマルチコンテキストの動作

マルチスレッドおよびマルチコンテキスト アプリケーションがアクティブの場合、クライアントのライフサイクルは次の 3 つのフェーズから構成されます。

起動フェーズ

起動フェーズでは、次の操作が行われます。

注意 : Oracle Tuxedo システムから独立して動作するスレッドが存在する場合もあります。ここでは、そのようなスレッドについては説明していません。
クライアント スレッドの複数コンテキストへの参加

Oracle Tuxedo マルチコンテキスト アプリケーションのクライアントは、次の規則に従う限り、複数のアプリケーションに対応付けることができます。

クライアントが複数のコンテキストに参加するには、TPINFO データ型の flags 要素に TPMULTICONTEXTS フラグを設定して、tpinit() 関数を呼び出します。

TPMULTICONTEXTS フラグを設定して tpinit() 関数が呼び出されると、アプリケーションとの新しい対応付けが生成され、スレッドに対するカレントの対応付けが指定されます。新しい対応付けが生成される Oracle Tuxedo ドメインは、TUXCONFIG または WSENVFILE/WSNADDR 環境変数の値で決定されます。

クライアント スレッドの既存のコンテキストへの切り替わり

多くの ATMI 関数はコンテキスト単位で動作します。このような ATMI 関数のリストについては、「マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。コンテキスト単位で動作するには、対象コンテキストが現在のコンテキストであることが必要です。クライアントは複数のコンテキストに参加できますが、状況とスレッドにかかわらず現在のコンテキストになることができるコンテキストは 1 つだけです。

アプリケーション内でタスクの優先順位が移り、ほかの Oracle Tuxedo ドメインと通信する必要が発生した場合、あるコンテキストから別のコンテキストにスレッドを再割り当てした方がよい場合があります。

そのような場合、あるクライアント スレッドが tpgetctxt(3c) を呼び出し、返された現在のコンテキストを値として持つハンドルを別のクライアント スレッドに渡します。2 番目のスレッドは tpsetctxt(3c) を呼び出し、最初のスレッドで tpgetctxt(3c) から受け取ったハンドルを指定して、現在のコンテキストとの対応付けを確立します。

目的のコンテキストとの対応付けが確立されると、2 番目のスレッドはコンテキスト単位で動作する ATMI 関数を使用してタスクを実行できるようになります。詳細については、「マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。

作業フェーズ

このフェーズでは、各スレッドによって処理が行われます。次は、行われる処理の例です。

サービス要求

スレッドは、同期要求の場合は tpcall()、非同期要求の場合は tpacall() を呼び出して、サーバに要求を送ります。tpcall() で要求を送った場合、以降操作を行わなくても応答を受け取ることができます。

サービス要求に対する応答

tpacall() でサービスの非同期要求を送った場合、同じコンテキスト内のスレッドは tpgetrply() を呼び出して応答を受け取ります。このスレッドは、要求を送ったスレッドと同じスレッドではない場合もあります。

トランザクション

あるスレッドがトランザクションを開始すると、そのスレッドのコンテキストを共有するすべてのスレッドでそのトランザクションが共有されます。

コンテキスト内の多くのスレッドでトランザクションに関する処理が行われますが、トランザクションをコミットまたはアボートできるのは 1 つのスレッドだけです。トランザクションをコミットまたはアボートするスレッドは、トランザクションを開始したスレッドである必要はなく、トランザクションを処理しているどのスレッドでもかまいません。スレッド アプリケーションでは、通常のトランザクション規則に従うために、適切に同期を行う必要があります。たとえば、未終了の RPC 呼び出しや会話がある場合に、トランザクションをコミットすることはできません。また、トランザクションがコミットまたはアボートされた後で、そのトランザクションに対する呼び出しを行うことはできません。プロセスは、アプリケーションの各対応付けに対して、1 つのトランザクションの一部にだけなることができます。

アプリケーションの 1 つのスレッドが tpcommit() を呼び出し、それと同時に別のスレッドが RPC 呼び出しまたは会話型呼び出しを行うと、これらの呼び出しは特定の順序で呼び出されたものとして処理されます。アプリケーション コンテキストは、シングルスレッド プログラムとシングルコンテキスト プログラムに対する制約と同じ制約に従って、tpsuspend() を呼び出してトランザクションを一時的に中断し、別のトランザクションを開始します。

非請求メッセージ

マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションの各コンテキストでは、非請求メッセージを次の 3 種類のいずれかの方法で処理できます。

処理方法
設定
非請求メッセージの無視
TPU_IGN
ディップ イン通知
TPU_DIP
専用のスレッド通知
(C 言語のアプリケーションのみで利用可能です)
TPU_THREAD

以下の事柄に注意してください。

専用のスレッド通知の場合、非請求メッセージの受信と、非請求メッセージ ハンドラのディスパッチに別々のスレッドが使用されます。あるコンテキストで一度に実行できる非請求メッセージ ハンドラは 1 つだけです。

スレッドがサポートされていない Oracle Tuxedo システム用プラットフォームで tpinit() が呼び出された場合に、スレッドがサポートされていないプラットフォーム上で TPU_THREAD 通知が要求されたことを示すパラメータが指定されていると、tpinit()-1 を返して tperrnoTPEINVAL を設定します。UBBCONFIG(5) のデフォルトの NOTIFY オプションが THREAD に設定されている場合に、特定のマシンでスレッドを利用できないと、そのマシンのデフォルトの機能は DIPIN になります。このような動作の相違があるので、スレッドがサポートされているマシンとサポートされていないマシンが混在するコンフィグレーションでは、管理者はすべてのマシンにデフォルトを指定できます。ただし、そのマシンで利用できない機能をクライアントが明示的に要求することはできません。

tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol() を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol() を再度呼び出すと、変更できます。

プロセスが同じアプリケーションと複数の対応付けを持つ場合、各対応付けに異なる CLIENTID を割り当てられ、非請求メッセージを特定のアプリケーションとの対応付けに送信できるようになります。プロセスが同じアプリケーションと複数の対応付けを持つ場合、ブロードキャスト基準を満たすアプリケーションの各対応付けに任意の tpbroadcast() が別々に送信されます。非請求メッセージを受信する場合のディップ イン チェックでは、カレントのアプリケーションとの対応付けに送信されるメッセージだけが対象となります。

非請求メッセージ ハンドラでは ATMI 関数を利用できるほか、非請求メッセージ ハンドラ内で tpgetctxt(3c) を呼び出すことができます。そのため、非請求メッセージ ハンドラは別のスレッドを生成して、同じコンテキスト内で必要となる実質的な ATMI 作業を行うことができるようになります。

ユーザ ログで保持されるスレッド固有の情報

userlog(3c) を使用すると、各アプリケーション内の各スレッドに対して次の識別情報が記録されます。

process_ID.thread_ID.context_ID

スレッドがサポートされていないプラットフォームやシングルコンテキスト アプリケーションに対しては、エントリの thread_ID フィールドと context_ID フィールドにプレースホルダが出力されます。

TM_MIB(5) では、この機能は T_ULOG クラスの TA_THREADID フィールドと TA_CONTEXTID フィールドでサポートされています。

完了フェーズ

このフェーズでは、クライアント プロセスの終了時に、カレントのコンテキストおよび対応付けられたすべてのスレッドに代わって 1 つのスレッドが tpterm() を呼び出してそのアプリケーションとの対応付けを終了します。ほかの ATMI 関数と同じように、tpterm() は現在のコンテキストに対して処理を行います。tpterm() は、終了するコンテキストに対応付けされたすべてのスレッドに影響し、これらのスレッドで共有されるすべてのコンテキストを終了します。

アプリケーションの設計が適切であれば、特定のコンテキスト内のすべての処理が完了してから tpterm() が呼び出されます。tpterm() が呼び出される前に、すべてのスレッドが同期していなければなりません。

関連項目

サーバでのサーバ ディスパッチ スレッドのマルチスレッドとマルチコンテキストの動作

マルチスレッドおよびマルチコンテキスト アプリケーションがアクティブの場合、サーバで行われる処理は次の 3 つのフェーズに分類できます。

起動フェーズ

起動フェーズで行われる処理は、コンフィグレーション ファイルの MINDISPATCHTHREADSMAXDISPATCHTHREADS パラメータの値によって異なります。

MINDISPATCHTHREADS の値
MAXDISPATCHTHREADS の値
結果
0
> 1
  1. Oracle Tuxedo システムがスレッド ディスパッチャを生成します。
  2. ディスパッチャが tpsvrinit() を呼び出して、アプリケーションに参加します。
> 0
> 1
  1. Oracle Tuxedo システムがスレッド ディスパッチャを生成します。
  2. ディスパッチャが tpsvrinit() を呼び出して、アプリケーションに参加します。
  3. Oracle Tuxedo システムがサービス要求を処理する新しいスレッドと、そのスレッドに対するコンテキストを生成します。
  4. システムで生成された新しいスレッドがそれぞれ tpsvrthrinit(3c) を呼び出して、アプリケーションに参加します。

作業フェーズ

このフェーズでは、次の処理が行われます。

サーバ ディスパッチ スレッドの使用方法

クライアントのサービス要求への応答として、サーバ ディスパッチャは設定可能な最大数まで複数のスレッドを 1 つのサーバに生成します。このサーバは、各種のクライアント要求に同時に割り当てることができます。サーバが tpinit() を呼び出すことはできません。

各ディスパッチ スレッドは、別々のコンテキストと対応付けられています。この機能は会話型サーバと RPC サーバの両方で有用です。特に、会話型サーバではこの機能を利用できないと、ほかの会話接続がサービスを待っている間、クライアント サイドの会話をアイドル状態で待つことになります。

この機能は、UBBCONFIG(5) ファイルの SERVERS セクションと TM_MIB(5) の次のパラメータで制御されます。

UBBCONFIG パラメータ
MIB パラメータ
デフォルト値
MINDISPATCHTHREADS
TA_MINDISPATCHTHREADS
0
MAXDISPATCHTHREADS
TA_MAXDISPATCHTHREADS
1
THREADSTACKSIZE
TA_THREADSTACKSIZE
0 (オペレーティング システムのデフォルト値)

BBL によるシステム プロセスの正常性チェック

BBL は定期的にサーバを検証します。特定のサービス要求の実行に時間がかかりすぎている場合、BBL はそのサーバを強制終了します。そして、指定されている場合は、そのサーバを再起動します。BBL がマルチコンテキスト サーバを強制終了した場合、プロセスを強制終了した結果として、実行中のそのほかのサービス呼び出しも終了します。

また、BBL はタイムアウト値を超えてメッセージの受信を待機しているプロセスまたはスレッドにメッセージを送信します。すると、ブロッキング メッセージ受信への呼び出しが、タイムアウトを示すエラーを返します。

システムで保持されるサーバ スレッドの統計

Oracle Tuxedo システムでは、各サーバに対して次の統計情報が保持されます。

ユーザ ログで保持されるスレッド固有の情報

userlog(3c) を使用すると、各アプリケーション内の各スレッドに対して次の識別情報が記録されます。

process_ID.thread_ID.context_ID

スレッドがサポートされていないプラットフォームやシングルコンテキスト アプリケーションに対しては、エントリの thread_ID フィールドと context_ID フィールドにプレースホルダが出力されます。

TM_MIB(5) では、この機能は T_ULOG クラスの TA_THREADID フィールドと TA_CONTEXTID フィールドでサポートされています。

完了フェーズ

アプリケーションを停止すると、tpsvrthrdone(3c)tpsvrdone(3c) が呼び出されて、リソース マネージャのクローズなど、必要な終了処理が行われます。

関連項目

サーバのアプリケーション生成スレッドのマルチスレッドとマルチコンテキストの動作

オペレーティング システム関数を使用して、Tuxedo アプリケーション サーバ内に新しいスレッドを追加できます。最初、アプリケーション生成サーバ スレッドは、どの Tuxedo コンテキストにも関連していません。アプリケーション生成のスレッドは、次のように動作します。

アプリケーション生成のサーバ スレッドは別の Tuxedo コンテキストを生成し、tpappthrinit(3c) を使用してこのコンテキストに自身を対応付けることができます。アプリケーション生成のサーバ スレッドがアクティブな場合、tpappthrinit(3c) によって生成された Tuxedo コンテキストのライフサイクルは、次の 3 つのフェーズから構成されます。

起動フェーズ

アプリケーション生成のサーバ スレッドは Tuxedo コンテキストを生成し、tpappthrinit(3c) を呼び出すことによってこのコンテキストに自身を対応付けます。tpappthrinit(3c) によって生成されたコンテキストは、アプリケーション サーバが存在するドメインに接続します。

必要に応じて、tpappthrinit(3c) を正常に呼び出した後、サーバ内のアプリケーション生成のスレッドが tpgetctxt(3c) を呼び出し、返されるハンドル (現在のコンテキストの値) を同じプロセス内の別のアプリケーション スレッドに渡します。

作業フェーズ

各アプリケーション生成のサーバ スレッドによって、次の処理が行われます。

アプリケーション生成のサーバ スレッドで実行されるこれらの処理は、クライアント プログラムの場合と同様の特徴を持っています。詳細については、「クライアントでのマルチスレッドとマルチコンテキストの動作」を参照してください。

注意: アプリケーション生成のサーバ スレッドは、tpreturn() および tpforward() を呼び出すことはできません。

アプリケーション生成のサーバ スレッドは、非請求メッセージを送信することはできますが、受信することはできません。

ユーザ ログで保持されるスレッド固有の情報

userlog(3c) を使用すると、サーバの各アプリケーション生成スレッドに対する識別情報 (process_ID.thread_ID.context_ID) が記録されます。

TM_MIB(5) では、この機能は T_ULOG クラスの TA_THREADID フィールドと TA_CONTEXTID フィールドでサポートされています。

完了フェーズ

アプリケーション生成のサーバ スレッドは処理が終了すると、tpappthrterm(3c) を呼び出して現在のコンテキストを終了します。

tpappthrterm(3c) は、同じコンテキストで現在動作しているすべてのアプリケーション生成のサーバ スレッドに影響を与えます。終了されるコンテキストでほかのアプリケーション生成のサーバ スレッドが動作している場合は、tpappthrterm(3c) を呼び出さないようにしてください。

アプリケーションの設計が適切であれば、特定のコンテキスト内のすべての処理が完了してから tpappthrterm(3c) が呼び出されます。アプリケーション スレッドが tpappthrterm(3c) を呼び出す前に、すべてのアプリケーション スレッドが同期しているかを確認してください。

関連項目

クライアントでのマルチスレッドとマルチコンテキストの動作

マルチスレッドおよびマルチコンテキスト アプリケーションの設計上の検討事項

サーバのアプリケーション生成スレッドでマルチコンテキストを使用するためのコーディング

サーバでサーバ ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング

マルチスレッド クライアントのコーディング

マルチスレッドおよびマルチコンテキスト アプリケーションの設計上の検討事項

マルチスレッドおよびマルチコンテキスト アプリケーションは、一部の Oracle Tuxedo ドメインでは正しく動作しますが、すべてのドメインで正しく動作するとは限りません。そのようなアプリケーションを作成する場合、次の事項について検討する必要があります。

環境の要件

マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションの開発では、開発環境と実行時環境に関して次の内容を検討します。

設計の要件

マルチスレッド アプリケーションやマルチコンテキスト アプリケーションの設計では、次の内容を検討します。

マルチスレッドやマルチコンテキストに適するアプリケーションのタスク

次の表は、アプリケーションをマルチスレッドまたはマルチコンテキストにすべきかどうかを判断するための参考となる検討事項を示しています。この表だけでは十分ではないので、個々の要件に基づいてほかの事項も検討してください。

そのほかの検討事項については、マルチスレッド アプリケーションやマルチコンテキスト アプリケーションのプログラミングに関する書籍を参照してください。

検討事項
検討事項に該当する場合に使用する機能
ドメイン機能を使用せずに、クライアントが複数のアプリケーションに接続する必要があるか
マルチコンテキスト。
アプリケーション内でクライアントが多重化の機能を果たすか。たとえば、アプリケーション内の 1 つのマシンがそのほかの 100 台のマシンの「代理」に指定されているか
マルチコンテキスト。
クライアントでマルチコンテキストが使用されるか
マルチスレッド。各コンテキストにスレッドを 1 つずつ割り当てると、コードを簡略化できます。
クライアントが 2 つ以上のタスクを長時間個別に実行することで、並列処理によるパフォーマンスがスレッド同期のコストと複雑さを上回るか
マルチスレッド。
1 つのサーバで複数の要求を同時に処理するか
マルチスレッド。MAXDISPATCHTHREADS に 1 より大きな値を割り当てます。このように設定すると、1 つのサーバで複数のクライアントをそのクライアントのスレッドで処理できるようになります。
アプリケーション生成のサーバ スレッドで ATMI 呼び出しを実行するか
マルチスレッド。
アプリケーション生成のサーバ スレッドは別の Tuxedo コンテキストを生成し、tpappthrinit(3c) を呼び出すことによってこのコンテキストに自身を対応付けます (この機能は Tuxedo 10g リリース 3 (10.3) で利用できます)。
クライアントまたはサーバに複数のスレッドがある場合、各スレッドでわずかな処理を行った後でもスレッドを同期する必要があるか
マルチスレッドを使用しません。

必要なアプリケーションと接続の数

アクセスするアプリケーションの数と、確立する接続の数を決定します。

同期に関する検討事項

これは設計段階での重要な検討事項です。このマニュアルでは、この内容について取り上げていません。マルチスレッド アプリケーションやマルチコンテキスト アプリケーションのプログラミングに関する書籍を参照してください。

アプリケーションの移植

後でアプリケーションを移植する必要がある場合、オペレーティング システムに応じて異なる関数が使用されていることに注目してください。あるプラットフォームで作成した初期バージョンのアプリケーションを後で移植する場合、異なる関数でコードを書き直すためにどれだけのリソース時間が必要なのかを考慮する必要があります。

最適なスレッド モデル

現在使用されているマルチスレッド プログラムには、次のようなモデルがあります。

スレッド モデルについては、このマニュアルでは取り上げていません。アプリケーションのプログラミング モデルを選択する場合は、利用できるすべてのモデルを調べて、設計の要件を慎重に検討してください。

ワークステーション クライアントの相互運用性に関する制約

リリース 7.1 の Workstation クライアントと 7.1 以前の Oracle Tuxedo システムに基づくアプリケーションとの相互運用性は、次のどの場合でもサポートされています。

Oracle Tuxedo リリース 7.1 のワークステーション クライアントで、1 つのコンテキストに複数のスレッドがある場合は、リリース 7.1 より前の Oracle Tuxedo システムとは相互運用しません。

関連項目

 


マルチスレッドおよびマルチコンテキスト アプリケーションの実装

マルチスレッドおよびマルチコンテキスト アプリケーションのプログラミング開始前のガイドライン

コーディングを開始する前に、次の内容や条件を満たしていることを確認してください。

マルチスレッド アプリケーションに必要な条件

開発プロジェクトを開始する前に、開発環境が次の条件を満たしていることを確認します。

マルチスレッド アプリケーションのプログラミングでの一般的な検討事項

マルチスレッド プログラムは、十分に経験を持つプログラマがコーディングします。特に、次のようなマルチスレッド固有の設計に関する基本的な知識があることが必要です。

これらは検討事項の一部にすぎず、ここに記せないほど多くの検討事項があります。マルチスレッド プログラムをコーディングするプログラマは、それらの検討事項を熟知していることが前提となります。これらの検討事項については、マルチスレッド アプリケーションのプログラミングに関する書籍を参照してください。

同時実行性に関する検討事項

マルチスレッドを使用すると、1 つのアプリケーションの異なるスレッドが同じ会話で並列処理を行うことができるようになります。この方法はお勧めしませんが、Oracle Tuxedo システムで禁止されているわけではありません。異なるスレッドによって同じ会話で並列処理が行われると、システムは同時呼び出しが任意の順序で行われたように動作します。

複数のスレッドを使ってプログラミングする場合、ミューテックスなどの同時実行性制御関数を使用して、スレッド間の同時実行性を管理する必要があります。以下は、同時実行性制御が必要になる 3 つの例です。

関連項目

クライアントでマルチコンテキストを使用するためのコーディング

この節では、以下の内容について説明します。

アプリケーションでトランザクションを使用する場合、トランザクションのマルチコンテキストの結果についても注目します。詳細については、「マルチスレッドおよびマルチコンテキスト アプリケーションにおけるトランザクションのコーディング規則」を参照してください。

注意 : この節で示す手順とサンプル コードは、Oracle Tuxedo システムで提供される C 言語のライブラリ関数を参照します。それらに相当する COBOL ライブラリ関数も利用できます。詳細については、『Tuxedo COBOL リファレンス』を参照してください。

コンテキストの属性

コンテキストを使用する場合、コーディングで以下の事柄に注意してください。

初期化時のマルチコンテキストの設定

クライアントがアプリケーションに参加する準備ができたら、次のサンプル コードに示すように、TPMULTICONTEXTS フラグを設定して tpinit() を指定します。

コード リスト 10-1 クライアントのマルチコンテキスト アプリケーションへの参加
#include <stdio.h>
#include <atmi.h>

TPINIT * tpinitbuf;

main()
{
tpinitbuf = tpalloc(“TPINIT”, NULL, TPINITNEED(0));

tpinitbuf->flags = TPMULTICONTEXTS;
.
.
.
if (tpinit (tpinitbuf) == -1) {
    		ERROR_PROCESSING_CODE
}
.
.
.
}

新しいアプリケーションとの対応付けが生成され、TUXCONFIG または WSENVFILE/WSNADDR 環境変数で指定された Oracle Tuxedo ドメインに割り当てられます。

注意 : 1 つのプロセスでは、tpinit() へのすべての呼び出しに TPMULTICONTEXTS フラグを含めるか、または tpinit() へのすべての呼び出しにこのフラグを含めません。この規則には、例外が 1 つあります。つまり、tpterm() への呼び出しが正常に終了して、クライアントのすべてのアプリケーション対応付けが終了した場合、次に tpinit() を呼び出すときに必ずしも TPMULTICONTEXTS フラグを含む必要のない状態にプロセスが復元されます。

マルチコンテキスト クライアントのセキュリティの実装

同じプロセス内の各アプリケーションとの対応付けには、別個にセキュリティ検証を行う必要があります。検証の内容は、アプリケーションで使用されているセキュリティ メカニズムのタイプによって異なります。たとえば、Oracle Tuxedo アプリケーションでは、システム レベルのパスワードまたはアプリケーション パスワードを使用します。

マルチコンテキスト アプリケーションのプログラマは、アプリケーションで使用するセキュリティのタイプを決定し、そのセキュリティをプロセス内の各アプリケーションとの対応付けに実装します。

クライアント終了前のスレッドの同期

クライアントをアプリケーションから切断する準備ができたら、tpterm() を呼び出します。ただし、マルチコンテキスト アプリケーションでは、tpterm() を呼び出すと現在のコンテキストが破棄されることに注目してください。その場合、現在のコンテキストで動作しているすべてのスレッドが影響を受けます。アプリケーション プログラマは、tpterm() が不意に呼び出されることがないように、複数のスレッドを使用する場合は注意してください。

まだ動作中のスレッドがあるコンテキストでは、tpterm() を呼び出さないようにします。そのような状況で tpterm() を呼び出すと、そのコンテキストと対応付けられていたほかのスレッドが特別な無効コンテキスト状態になります。無効コンテキスト状態では、大部分の ATMI 関数を使用できなくなります。無効コンテキスト状態からスレッドを解放するには、tpsetctxt(3c) または tpterm() を呼び出します。良く設計されたアプリケーションでは、無効コンテキスト状態が生じることはありません。

注意 : Oracle Tuxedo システムでは、COBOL アプリケーションのマルチスレッドはサポートされていません。

コンテキストの切り替え

次は、2 つのコンテキストからサービスを呼び出すクライアントで行われる処理の手順をまとめたものです。

  1. TUXCONFIG 環境変数に firstapp で必要な値を設定します。
  2. TPMULTICONTEXTS フラグを設定して tpinit() を呼び出し、最初のアプリケーションに参加します。
  3. tpgetctxt(3c) を呼び出して、現在のコンテキストへのハンドルを取得します。
  4. tuxputenv() を呼び出して、TUXCONFIG 環境変数の値を secondapp コンテキストに必要な値に切り替えます。
  5. TPMULTICONTEXTS フラグを設定して tpinit() を呼び出し、最初のアプリケーションに参加します。
  6. tpgetctxt(3c) を呼び出して、現在のコンテキストへのハンドルを取得します。
  7. tpsetctxt(3c) を呼び出して、firstapp コンテキストからコンテキストの切り替えを開始します。
  8. firstapp サービスを呼び出します。
  9. tpsetctxt(3c) を呼び出してクライアントを secondapp コンテキストに切り替え、secondapp サービスを呼び出します。
  10. tpsetctxt(3c) を呼び出してクライアントを firstapp コンテキストに切り替え、firstapp サービスを呼び出します。
  11. tpterm() を呼び出して、firstapp コンテキストを終了します。
  12. tpsetctxt(3c) を呼び出してクライアントを secondapp コンテキストに切り替え、secondapp サービスを呼び出します。
  13. tpterm() を呼び出して、secondapp コンテキストを終了します。

次のサンプル コードは、この手順を示しています。

注意 : コードを簡単にするために、エラー チェックは省略してあります。
コード リスト 10-2 クライアントでのコンテキストの切り替え
#include <stdio.h>
#include "atmi.h" /* Oracle Tuxedo ヘッダ ファイル */

#if defined(__STDC__) || defined(__cplusplus)
main(int argc, char *argv[])
#else
main(argc, argv)
int argc;
char *argv[];
#endif
{

TPINIT * tpinitbuf;
TPCONTEXT_T firstapp_contextID, secondapp_contextID;
/* TUXCONFIG が /home/firstapp/TUXCONFIG に設定されていることを前提とする */
/*
    * Oracle Tuxedo システムにマルチコンテキスト モードで接続 */
*/
tpinitbuf=tpalloc(“TPINIT”, NULL, TPINITNEED(0));
tpinitbuf->flags = TPMULTICONTEXTS;

if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}

/*
    * 現在のコンテキストへのハンドルを取得
*/
tpgetctxt(&firstapp_contextID, 0);

/*
    * tuxputenv を使用して TUXCONFIG の値を変更し、
    * 別のアプリケーションに参加 (tpinit)
*/ */
tuxputenv("TUXCONFIG=/home/second_app/TUXCONFIG");

/*
    * secondapp に参加 (tpinit)
*/
if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}

/*
    * secondapp のコンテキストへのハンドルを取得
*/
tpgetctxt(&secondapp_contextID, 0);

/*
    * tpgetctxt から取得したハンドルと tpsetctxt を使用して、
    * 2 つのコンテキスト間で切り替えが
* できる。firstapp から開始
*/

tpsetctxt(firstapp_contextID, 0);

/*
    * firstapp で提供されるサービスを呼び出し、
    * 次に secondapp に切り替える
*/

tpsetctxt(secondapp_contextID, 0);

/*
* secondapp で提供されるサービスを呼び出す
* 次に firstapp に戻る
*/

tpsetctxt(firstapp_contextID, 0);

/*
* firstapp で提供されるサービスを呼び出す。操作が終了したら
* firstapp のコンテキストを終了
*/

tpterm();

/*
* secondapp に戻る
*/

tpsetctxt(secondapp_contextID, 0);
/*
* secondapp で提供されるサービスを呼び出す。操作が終了したら
* secondapp のコンテキストを終了し、
* プログラムを終了
*/

tpterm();

return(0);
}

非請求メッセージの処理

非請求メッセージを処理する各コンテキストでは、非請求メッセージ ハンドラを設定するか、またはプロセス ハンドラのデフォルトが設定されている場合はそれを使用する必要があります。

tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol() を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol() を再度呼び出すと、変更できます。

ハンドラの設定は、シングルスレッド アプリケーションまたはシングルコンテキスト アプリケーションのハンドラを設定する場合と同じように行います。詳細については、「tpsetunsol()」を参照してください。

現在処理を行っているコンテキストを識別するには、非請求メッセージ ハンドラ内で tpgetctxt(3c) を使用します。

マルチスレッドおよびマルチコンテキスト アプリケーションにおけるトランザクションのコーディング規則

トランザクションを使用する場合、コーディングで以下の事柄に注意してください。

関連項目

サーバでサーバ ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング

ここでは、以下の内容について説明します。

注意 : この節で示す手順とサンプル コードは、Oracle Tuxedo システムで提供される C 言語のライブラリ関数を参照します。詳細については、『Oracle Tuxedo C リファレンス』を参照してください。COBOL アプリケーションではマルチコンテキスト サーバの生成に必要なマルチスレッドがサポートされていないので、C 言語の関数に相当する COBOL ルーチンは利用できません。

コンテキストの属性

コンテキストを使用する場合、コーディングで以下の事柄に注意してください。

マルチコンテキスト サーバでのサーバ ディスパッチ スレッドのコーディング規則

マルチコンテキスト サーバ使用する場合、コーディングで以下の規則に注意してください。

サーバおよびサーバ スレッドの初期化と終了

サーバとサーバ スレッドの初期化と終了には、Oracle Tuxedo システムで提供されるデフォルトの関数を使用できます。

表 10-1 初期化と終了を行うデフォルトの関数
処理内容
使用するデフォルトの関数
サーバの初期化
サーバ スレッドの初期化
サーバの終了
サーバ スレッドの終了

関連項目

サーバでのサーバ ディスパッチ スレッドのマルチスレッドとマルチコンテキストの動作

サーバのアプリケーション生成スレッドでマルチコンテキストを使用するためのコーディング

ここでは、以下の内容について説明します。

スレッドの生成

オペレーティング システムのスレッド関数を使用して、Tuxedo アプリケーション サーバに新しいスレッドを生成できます。これらの新しいアプリケーションは、Tuxedo システムから独立して動作できます。また、いずれかのサーバ ディスパッチ スレッドと同じコンテキストで動作することもできます。アプリケーション生成のサーバ スレッドは、tpappthrinit(3c) によって生成された別のコンテキストで動作することもできます。

コンテキストへのアプリケーション スレッドの対応付け

最初、アプリケーション生成サーバ スレッドは、どの Tuxedo コンテキストにも関連していません。ただし、初期化される前に呼び出された場合、ほとんどの ATMI 関数は暗黙的に tpinit() を実行します。サーバで tpinit() を呼び出すことは禁止されているので、そのような呼び出しを行うと問題が発生します。サーバ プロセスで tpinit() が呼び出されると、tpinit()-1 を返して tperrno(5)TPEPROTO を設定します。

そのため、アプリケーション生成のサーバ スレッドは、有効なコンテキストと対応付けを行ってから ATMI 関数を呼び出す必要があります。アプリケーション生成のサーバ スレッドは、次のように動作します。

既存のサーバ ディスパッチ コンテキストへのアプリケーション スレッドの対応付け

アプリケーション生成のサーバ スレッドを既存のサーバ ディスパッチ コンテキストに対応付けるには、以下の手順をコーディングします。

  1. サーバ ディスパッチ スレッド_A は、tpgetctxt(3c) を呼び出して現在のコンテキストへのハンドルを取得します。
  2. サーバ ディスパッチ スレッド_A は、tpgetctxt(3c) が返すハンドルをアプリケーション スレッド_B に渡します。
  3. アプリケーション スレッド_B は、tpsetctxt(3c) を呼び出してサーバ ディスパッチ スレッド_A から受け取ったハンドルを指定して、現在のコンテキストとの対応付けを作成します。
注意 : アプリケーション生成のサーバ スレッドは、tpreturn() または tpforward() (あるいはその両方) を呼び出すことはできません。元のサーバ ディスパッチ スレッドが tpreturn() または tpforward() を呼び出す前に、そのコンテキストにあったすべてのアプリケーション生成のサーバ スレッドは TPNULLCONTEXT または別の有効なコンテキストに切り替える必要があります。
注意 : この規則に違反すると、tpforward() または tpreturn() が失敗し、呼び出し側にサービス エラーが示されます。

マルチコンテキスト サーバでの既存のサーバ ディスパッチ コンテキストにアプリケーション スレッドを対応付けするためのサンプル コード

コード リスト 10-3 は、サービスが別のスレッドを生成して同じサーバ ディスパッチ コンテキストでそのサービスの作業を行うマルチコンテキスト サーバを示しています。このコードは、サーバでアプリケーション スレッドを生成する必要があるアプリケーションで使用します。オペレーティング システムのスレッド関数は、オペレーティング システムによって異なります。このサンプル コードでは、POSIX 関数と ATMI 関数が使用されています。

注意 : コードを簡単にするために、エラー チェックは省略してあります。また、Oracle Tuxedo システムによってディスパッチされたスレッドだけを使用するマルチコンテキスト サーバも省略してあります。そのようなサーバのコーディングは、スレッド セーフのプログラミング方法が使用されている場合、シングルコンテキスト サーバのコーディングとまったく同じです。
コード リスト 10-3 アプリケーション生成のサーバ スレッドがサーバ ディスパッチ コンテキストで動作するサンプル コード
#include <pthread.h>
#include <atmi.h>
void *withdrawalthread(void *);
struct sdata {
    TPCONTEXT_T ctxt;
    TPSVCINFO   *svcinfoptr;
};
void	
TRANSFER(TPSVCINFO *svcinfo)
{
    struct sdata  transferdata;
    pthread_t    withdrawalthreadid;
    tpgetctxt(&transferdata.ctxt, 0);
    transferdata.svcinfoptr = svcinfo;
pthread_create( &withdrawalthreadid, NULL,
withdrawalthread, &transferdata );
    tpcall("DEPOSIT", ...);
    pthread_join(withdrawalthreadid, NULL);
    tpreturn(TPSUCCESS, ...);
}
void *
withdrawalthread(void *arg)
{
    tpsetctxt(arg->ctxt, 0);
    tpopen();
    tpcall("WITHDRAWAL", ...);
    tpclose();
    tpsetctxt(TPNULLCONTEXT, 0);
    return(NULL);
}

アプリケーション生成のコンテキストへのアプリケーション スレッドの対応付け

サーバ内のアプリケーション生成のサーバ スレッドは別の Tuxedo コンテキストを生成し、tpappthrinit(3c) を呼び出してこのコンテキストに自身を対応付けることができます。

コンテキストの属性
アプリケーション生成のコンテキストでのサーバのアプリケーション生成スレッドのコーディング規則

マルチコンテキスト サーバでのアプリケーション生成のサーバ コンテキストにアプリケーション スレッドを対応付けするためのサンプル コード

コード リスト 10-4 は、サービスが別のスレッドを生成するマルチコンテキスト サーバを示しています。このコードは、サーバでアプリケーション スレッドを生成する必要があるアプリケーションで使用します。このアプリケーション生成のサーバ スレッドは別のコンテキストで動作します。オペレーティング システムのスレッド関数は、オペレーティング システムによって異なります。このサンプル コードでは、POSIX 関数と ATMI 関数が使用されています。

注意 : コードを簡単にするために、エラー チェックは省略してあります。
コード リスト 10-4 アプリケーション生成のサーバ スレッドがアプリケーション生成のコンテキストで動作するサンプル コード
#include <pthread.h>
#include <atmi.h>
void *withdrawalthread(void *);
void
TRANSFER(TPSVCINFO *svcinfo)
{
    pthread_t withdrawalthreadid;
    pthread_create( &withdrawalthreadid, NULL,
                    withdrawalthread, … );
    tpcall("DEPOSIT", ...);
    pthread_join(withdrawalthreadid, NULL);
    tpreturn(TPSUCCESS, ...);
}
void *
withdrawalthread(void *arg)
{
    tpappthrinit(NULL);
    tpopen();
    tpcall("WITHDRAWAL", ...);
    tpclose();
    tpappthrterm();
    return(NULL);
}

関連項目

サーバのアプリケーション生成スレッドのマルチスレッドとマルチコンテキストの動作

サーバでのサーバ ディスパッチ スレッドのマルチスレッドとマルチコンテキストの動作

マルチスレッド クライアントのコーディング

ここでは、以下の内容について説明します。

注意 : Oracle Tuxedo システムでは、COBOL アプリケーションのマルチスレッドはサポートされていません。

マルチスレッド クライアントのコーディング規則

マルチスレッド クライアントを使用する場合、コーディングで以下の規則に注意してください。

クライアントの複数のコンテキストへの初期化

クライアントを複数のコンテキストに参加させるには、TPINIT データ構造体の flags 要素に TPMULTICONTEXTS フラグを設定して tpinit() 関数を呼び出します。

1 つのプロセスでは、tpinit() へのすべての呼び出しに TPMULTICONTEXTS フラグを含めます。または、tpinit() へのすべての呼び出しにこのフラグを含めません。この規則には、例外が 1 つあります。つまり、tpterm() への呼び出しが正常に終了して、クライアントのすべてのアプリケーション対応付けが終了した場合、次に tpinit() を呼び出すときに必ずしも TPMULTICONTEXTS フラグを含む必要のない状態にプロセスが復元されます。

TPMULTICONTEXTS フラグを設定して tpinit() 関数が呼び出されると、アプリケーションとの新しい対応付けが生成され、スレッドに対するカレントの対応付けが指定されます。新しい対応付けが生成される Oracle Tuxedo ドメインは、TUXCONFIG または WSENVFILE/WSNADDR 環境変数の値で決定されます。

クライアント スレッドが TPMULTICONTEXTS フラグを設定せずに tpinit() を正常に実行した場合、クライアントのすべてのスレッドがシングルコンテキスト状態 (TPSINGLECONTEXT) になります。

tpinit() が失敗した場合、呼び出し側スレッドは元のコンテキスト、つまり tpinit() 呼び出しの前に操作していたコンテキスト状態のままになります。

まだ動作中のスレッドがあるコンテキストから tpterm() を呼び出すことはできません。このような状況やそれ以外の状況で tpterm() を呼び出した結果生じるコンテキスト状態については、「マルチコンテキスト状態の遷移」を参照してください。

クライアント スレッドのコンテキスト状態の変化

マルチコンテキストのアプリケーションでは、いろいろな関数を呼び出すと、呼び出し側スレッド、および呼び出し側プロセスと同じコンテキストでアクティブなその他のスレッドのコンテキスト状態が変化します。次の図は、tpinit()tpsetctxt(3c)、および tpterm() を呼び出した結果、変化したコンテキスト状態を示しています。tpgetctxt(3c) 関数を呼び出しても、コンテキスト状態は変化しません。

図 10-4 マルチコンテキスト状態の遷移

マルチコンテキスト状態の遷移

注意 : tpterm() がマルチコンテキスト状態 (TPMULTICONTEXTS) で実行しているスレッドによって呼び出されると、呼び出し側スレッドは NULL コンテキスト状態 (TPNULLCONTEXT) になります。終了するコンテキストに関連するその他すべてのスレッドは、無効コンテキスト状態 (TPINVALIDCONTEXT) に切り替わります。

次の図は、tpinit()tpsetctxt(3c)、および tpterm() を呼び出した結果、変化したコンテキスト状態を示しています。

表 10-2 クライアント スレッドのコンテキスト状態の変化
実行する関数
実行後のスレッドのコンテキスト状態
NULL コンテキスト
シングルコンテキスト
マルチコンテキスト
無効コンテキスト
TPMULTICONTEXTS が設定されていない tpinit()
シングルコンテキスト
シングルコンテキスト
エラー
エラー
TPMULTICONTEXTS が設定された tpinit()
マルチコンテキスト
エラー
マルチコンテキスト
エラー
TPNULLCONTEXT への tpsetctxt(3c)
NULL
エラー
NULL
NULL
コンテキスト 0 への tpsetctxt(3c)
エラー
シングルコンテキスト
エラー
エラー
コンテキスト > 0 への tpsetctxt(3c)
マルチコンテキスト
エラー
マルチコンテキスト
マルチコンテキスト
暗黙的な tpinit()
シングルコンテキスト
該当せず
該当せず
エラー
このスレッドでの tpterm()
NULL
NULL
NULL
NULL
このコンテキストの異なるスレッドでの tpterm()
該当せず
NULL
無効
該当せず

マルチスレッド環境での応答の取得

tpgetrply() は、tpacall() からの要求に対する応答だけを受け取ります。tpcall() からの要求は、マルチスレッドまたはマルチコンテキストのレベルに関係なく、tpgetrply() で取得することはできません。

tpgetrply() は、1 つのコンテキスト、つまり tpgetrply() の呼び出し側コンテキストだけで動作します。そのため、TPGETANY フラグを設定して tpgetrply() を呼び出すと、同じコンテキストで生成されたハンドルだけが考慮されます。同じように、あるコンテキストで生成されたハンドルを別のコンテキストで使用することはできません。ただし、同じコンテキストで動作するスレッドには、そのハンドルを使用できます。

tpgetrply() をマルチスレッド環境で呼び出す場合、以下の制約があります。

マルチスレッド マルチコンテキスト環境の環境変数

Oracle Tuxedo アプリケーションをマルチコンテキスト マルチスレッド環境で実行する場合、環境変数に関して以下の事柄に注意してください。

マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体

以下に示す ATMI 関数は、呼び出し側のアプリケーション コンテキストだけに影響します。

注意 : tpbroadcast() の場合、ブロードキャスト メッセージは特定のアプリケーションとの対応付けから送られたものとして識別されます。tpnotify(3c) の場合、通知は特定のアプリケーションとの対応付けから送られたものとして識別されます。tpinit() の注記については、「マルチスレッド クライアントでのプロセス単位の関数とデータ構造体」を参照してください。
注意 : tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol() を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol() を再度呼び出すと、変更できます。

マルチスレッド クライアントでのプロセス単位の関数とデータ構造体

以下に示す Oracle Tuxedo 関数は、呼び出し側のプロセス全体に影響します。

シングルコンテキスト モード、マルチコンテキスト モード、または非初期化モードのどれを使用するかは、プロセス全体に影響します。また、バッファ タイプ スイッチ、ビュー キャッシュ、および環境変数の値も、プロセス単位の関数です。

マルチスレッド クライアントでのスレッド単位の関数とデータ構造体

以下に示す関数は、呼び出し側のスレッドだけに影響します。

Ferror、Ferror32(5)tperrno(5)tpurcode(5)、および Uunix_err 変数は、各スレッドに固有です。

現在のコンテキストの ID は各スレッドに固有です。

マルチスレッド クライアントのサンプル コード

次のサンプル コードは、ATMI 呼び出しを使用するマルチスレッド クライアントを示しています。スレッド関数は、オペレーティング システムによって異なります。この例では、POSIX 関数が使用されています。

注意 : コードを簡単にするために、エラー チェックは省略してあります。
コード リスト 10-5 マルチスレッド クライアントのサンプル コード
#include <stdio.h>
#include <pthread.h>
#include <atmi.h>

TPINIT * tpinitbuf;
int timeout=60;
pthread_t withdrawalthreadid, stockthreadid;
TPCONTEXT_T ctxt;
void * stackthread(void *);
void * withdrawalthread(void *);

main()
{
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
/*
* このコードでは、withdrawal スレッドと deposit スレッドという別のスレッドを
* 使用して振り込みを行う。また、Oracle 株の現在の価格を
* 別のアプリケーションから取得し、送金した金額で
* 購入できる株数を計算する
*/

tpinitbuf->flags = TPMULTICONTEXTS;

/* 残りの tpinitbuf を設定 */
tpinit(tpinitbuf);

tpgetctxt(&ctxt, 0);
tpbegin(timeout, 0);
pthread_create(&withdrawalthreadid, NULL, withdrawalthread, NULL);
tpcall("DEPOSIT", ...);

/* withdrawal スレッドの完了を待機 */
pthread_join(withdrawalthreadid, NULL);

tpcommit(0);
tpterm();

/* stock スレッドの完了を待機 */
pthread_join(stockthreadid, NULL);

/* 結果を出力 */
printf("$%9.2f has been transferred \
from your savings account to your checking account.\n", ...);

printf("At the current Oracle stock price of $%8.3f, \
you could purchase %d shares.\n", ...);

exit(0);
}



void *
stockthread(void *arg)
{

      /* ほかのスレッドが tpinit() を呼び出しているので、
       * TUXCONFIG を再設定してもスレッドに影響しない
     */

tuxputenv("TUXCONFIG=/home/users/xyz/stockconf");
tpinitbuf->flags = TPMULTICONTEXTS;
     /* 残りの tpinitbuf を設定 */
tpinit(tpinitbuf);
tpcall("GETSTOCKPRICE", ...);
/* main() でもアクセスできる変数に株価を格納 */
tpterm();
return(NULL);
}



void *
withdrawalthread(void *arg)
{
/* 別のアプリケーションから株価を取得するために新しいスレッドを
* 生成
*/


pthread_create(&stockthreadid, NULL, stockthread, NULL);
tpsetctxt(ctxt, 0);
tpcall("WITHDRAWAL", ...);
return(NULL);
}

関連項目

マルチスレッド サーバのコーディング

ほとんどの場合、マルチスレッド サーバはマルチコンテキストでもあります。マルチスレッド サーバのコーディングについては、「サーバでサーバ ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング」を参照してください。

マルチスレッドおよびマルチコンテキスト アプリケーションのコードのコンパイル

buildserver(1)buildclient(1) など、コンパイルまたはビルドの実行可能ファイル用に Oracle Tuxedo システムで提供されるプログラムには、必要なコンパイラ フラグが自動的に設定されます。これらのツールを使用すると、コンパイル時にフラグを設定する必要がありません。

ただし、最終的なコンパイルの前に .c ファイルを .o ファイルにコンパイルする場合は、プラットフォーム固有のコンパイラ フラグを設定する必要があります。そのようなフラグは、単一のプロセスにリンクするすべてのコードに一貫して設定しなければなりません。

マルチスレッド サーバを生成する場合、-t オプションを指定して buildserver(1) コマンドを実行する必要があります。これはマルチスレッド サーバの場合に必須のオプションです。ビルド時にこのオプションが指定されておらず、その後、MAXDISPATCHTHREADS の値が 1 を超えるコンフィグレーション ファイルを使用して新しいサーバを起動すると、警告メッセージがユーザ ログに記録され、サーバはシングルスレッドの動作に戻ります。

マルチスレッド環境で .c ファイルを .o ファイルにコンパイルする場合に必要なオペレーティング システム固有のコンパイラ パラメータを識別するには、-v オプションを指定して buildclient(1) または buildserver(1) をテスト ファイルで実行します。

関連項目

 


マルチスレッドおよびマルチコンテキスト アプリケーションのテスト

ここでは、以下の内容について説明します。

マルチスレッドおよびマルチコンテキスト アプリケーションのテスト時の推奨事項

マルチスレッドやマルチコンテキストのコードをテストする場合、以下を行うことをお勧めします。

マルチスレッドおよびマルチコンテキスト アプリケーションのトラブルシューティング

エラーの原因を調べる場合、まず TPMULTICONTEXTS フラグが設定されているかどうか、またその設定内容を確認します。このフラグが設定されていないこと、または正しく設定されていないことが原因でよくエラーが起こります。

tpinit( ) の TPMULTICONTEXTS フラグの間違った使用

TPMULTICONTEXTS フラグを使用できない場合にこのフラグがプロセスに設定されているとき、または TPMULTICONTEXTS を設定する必要がある場合に設定されていないとき、tpinit()-1 を返し、tperrnoTPEPROTO を設定します。

TPMULTICONTEXTS が設定されていない場合の tpinit() の呼び出し

TPMULTICONTEXTS が設定されていない場合に tpinit() が呼び出されると、この関数はシングルコンテキスト アプリケーションで呼び出されたときと同じように動作します。tpinit() が既に 1 回呼び出されている場合、それ以降の tpinit() 呼び出しで TPMULTICONTEXTS フラグが設定されていなくても、この関数は正常に終了します。これは、アプリケーション内の TUXCONFIG または WSNADDR 環境変数の値が変更されている場合にも当てはまります。TPMULTICONTEXTS フラグを設定せずに tpinit() を呼び出すことは、マルチコンテキスト モードではできません。

クライアントがアプリケーションに参加していない場合に、tpinit() を呼び出す別の関数の呼び出しの結果として、暗黙的に tpinit() が呼び出されると、Oracle Tuxedo システムでは TPMULTICONTEXTS フラグが設定されずに tpinit() が呼び出されたと解釈されます。これは、以降の tpinit() 呼び出しでどのフラグが使用されるかを判断するためです。

ほとんどの ATMI 関数は、既にマルチコンテキスト モードで動作しているプロセスのコンテキストに対応付けされていないスレッドに呼び出された場合、tperrno(5)=TPEPROTO が設定されて失敗します。

スレッドのスタック サイズの不足

一部のオペレーティング システムでは、オペレーティング システムのデフォルトのスレッド スタック サイズが Oracle Tuxedo システムで使用するには十分ではありません。Compaq Tru64 UNIX と UnixWare の 2 つのオペレーティング システムは、サイズが小さいことが認識されています。デフォルトのスレッド スタック サイズのパラメータが使用されている場合に、スタックを多用する関数がメイン スレッド以外のスレッドで呼び出されると、これらのプラットフォーム上のアプリケーションはコア ダンプします。通常、生成されるコア ファイルから、スタック サイズの不足が問題の原因であることはわかりません。

サーバ ディスパッチ スレッドやクライアントの非請求メッセージ スレッドなど、Oracle Tuxedo システムで独自のスレッドが生成される場合、これらのプラットフォームのデフォルトのスタック サイズのパラメータを適切な値に調整できます。ただし、アプリケーションで独自のスレッドが生成される場合、アプリケーションで十分なスタック サイズを指定する必要があります。Oracle Tuxedo システムにアクセスするスレッドには、最低 128 K を指定してください。

Compaq Tru64 UNIX および POSIX スレッドが使用されるそのほかのシステムでは、スレッドのスタック サイズは、pthread_create() を呼び出す前に pthread_attr_setstacksize() を呼び出して指定します。UnixWare では、スレッドのスタック サイズは thr_create() の引数として指定されます。この問題の詳細については、お使いのオペレーティング システムのマニュアルを参照してください。

マルチスレッドおよびマルチコンテキスト アプリケーションのエラー処理

エラーはユーザ ログに記録されます。シングルコンテキスト モードでもマルチコンテキスト モードでも、各エラーに対して次の情報が記録されます。

process_ID.thread_ID.context_ID

関連項目


  ページの先頭       前  次