マルチスレッドおよびマルチコンテキストATMIアプリケーションのプログラミング
マルチスレッド/マルチコンテキストATMIアプリケーションのプログラミングに対するサポート
Oracle Tuxedoシステムでは、次のアプリケーションがサポートされています。
|
•
|
カーネル・レベルのスレッド・パッケージ(ユーザー・レベルのスレッド・パッケージはサポートされていません)。
|
|
•
|
C言語で記述されたマルチスレッド・アプリケーション(COBOLでのマルチスレッド・アプリケーションはサポートされていません)。
|
|
•
|
C言語またはCOBOL言語で記述されたマルチコンテキスト・アプリケーション。
|
お使いのオペレーティング・システムでPOSIXスレッド関数と共にほかのスレッド関数がサポートされている場合は、POSIXスレッド関数を使用することをお薦めします。この関数を使用すると、後でコードをほかのプラットフォームに簡単に移植できます。
お使いのプラットフォームでカーネル・レベルのスレッド・パッケージ、C言語の関数、またはPOSIX関数がサポートされているかどうかを確認するには、
『Oracle Tuxedoシステムのインストール』で、使用しているオペレーティング・システムのデータ・シートを参照してください。
マルチスレッドおよびマルチコンテキスト・アプリケーションに関するプラットフォーム固有の検討事項
多くのプラットフォームには、マルチスレッドおよびマルチコンテキスト・アプリケーション固有の要件があります。プラットフォーム固有の要件については、
『Oracle Tuxedoシステムのインストール』に説明があります。お使いのプラットフォームの要件については、該当するデータ・シートを参照してください。
マルチスレッド/マルチコンテキストATMIアプリケーションの計画と設計
Oracle Tuxedoシステムでは、単一のプロセスで複数のタスクを同時に実行できます。このようなプロセスを実装するプログラミング手法は
マルチスレッドおよび
マルチコンテキストと呼ばれます。この項では、これらの手法に関する基本事項について説明します。
マルチスレッドとは、1つのプロセスに複数の実行単位が含まれている処理方法です。マルチスレッド・アプリケーションでは、同じプロセスから同時に複数の呼出しを行うことができます。たとえば、個々のプロセスが1つの未終了の
tpcall(3c)に制限されることはありません。
サーバーのマルチスレッドでは、アプリケーション生成のスレッドがシングル・コンテキスト・サーバーで使用される場合を除き、マルチコンテキストが必要です。マルチスレッドのシングル・コンテキスト・アプリケーションを作成する唯一の方法は、アプリケーション生成のスレッドを使用することです。
Oracle Tuxedoシステムでは、C言語で記述されたマルチスレッド・アプリケーションがサポートされています。COBOL言語のマルチスレッド・アプリケーションはサポートされていません。
図10-1は、マルチスレッド・クライアントが3つのサーバーに対して同時に呼出しを行う方法を示しています。
マルチスレッド・アプリケーションでは、同じサーバーで複数のサービス・ディスパッチ・スレッドを使用できるので、アプリケーションに対して起動するサーバー数が少なくて済みます。
図10-2は、異なるクライアントに対して、サーバー・プロセスが同時に複数のスレッドをディスパッチする方法を示しています。
コンテキストはドメインへの関連付けです。マルチコンテキストを使用すると、1つのプロセスで次のいずれかが可能になります。
マルチコンテキストは、クライアントとサーバーの両方で使用できます。サーバーでマルチコンテキストを使用すると、マルチスレッドも使用することになります。
コンテキストの特徴の詳細は、次のいずれかの項で「コンテキストの属性」を参照してください。
Oracle Tuxedoシステムでは、C言語またはCOBOL言語のいずれかで記述されたマルチコンテキスト・アプリケーションがサポートされています。ただし、サポートされるマルチスレッド・アプリケーションは、C言語で記述されたものだけです。
図10-3は、ドメイン内でのマルチコンテキスト・クライアント・プロセスの動作を示しています。各矢印はサーバーへの未終了の呼出しを表します。
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションのライセンス
ライセンスの関係で、各コンテキストは1人のユーザーとしてカウントされます。1つのコンテキストで複数のスレッドを使用するために、ライセンスを追加する必要はありません。例:
|
•
|
アプリケーションAに対応する2つのコンテキストと、アプリケーションBに対応する1つのコンテキストを持つプロセスの場合、アプリケーションAに2人、アプリケーションBに1人の合計3人のユーザーとしてカウントされます。
|
|
•
|
1つのアプリケーションにアクセスする複数のスレッドが同じコンテキスト内にあるプロセスの場合、ユーザーは1人としてカウントされます。
|
マルチスレッド/マルチコンテキストATMIアプリケーションの利点と問題点
マルチスレッドとマルチコンテキストを適切な状況で使用すると、Oracle Tuxedoアプリケーションのパフォーマンスを向上できます。ただし、これらの手法を取り入れる前に、潜在的な利点と問題点について理解しておくことが大切です。
マルチスレッド/マルチコンテキストATMIアプリケーションの利点
マルチスレッドおよびマルチコンテキストATMIアプリケーションには、以下の利点があります。
マルチスレッドとマルチコンテキストを併用すると、一部のアプリケーションではパフォーマンスと同時実行性が向上します。また、一部のアプリケーションでは、パフォーマンスが変わらないか、逆に低下する場合があります。パフォーマンスへの影響は、使用しているアプリケーションによって異なります。
|
•
|
リモート・プロシージャ・コールと会話のコーディングの単純化
|
アプリケーションによっては、異なるリモート・プロシージャ・コールと会話を別々のスレッドでコーディングした方が、同じスレッドで管理するより簡単な場合があります。
Oracle Tuxedoクライアントを同時に複数のアプリケーションに接続できます。
1つのサーバーで複数のサービス・スレッドをディスパッチできるので、アプリケーションに対して起動するサーバーの数を減らすことができます。このように複数のスレッドをディスパッチできる機能は、特に会話型サーバーの場合に有用です。会話型サーバーにこの機能がない場合、会話が終了するまで1つのクライアントしか使用できなくなります。
アプリケーションで、クライアント・スレッドがMicrosoft Internet Information Server APIまたはNetscape Enterprise Serverインタフェース(NSAPI)によって生成される場合、これらのツールの機能を最大限に利用するにはマルチスレッドが不可欠です。ほかのツールについても同じことが言えます。
マルチスレッド/マルチコンテキストATMIアプリケーションの問題点
マルチスレッドおよびマルチコンテキストATMIアプリケーションには、以下の問題点があります。
マルチスレッドおよびマルチコンテキスト・アプリケーションのコーディングは簡単ではありません。このようなアプリケーションのコーディングは、十分な経験を持つプログラマだけが行うことができます。
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションで発生したエラーを再現することは、シングル・スレッドおよびシングル・コンテキスト・アプリケーションで再現するより難しい作業です。そのため、エラー発生時にその根本的な原因を特定して検証することがさらに難しくなります。
スレッド間の同時実行性の管理は難しい作業であり、アプリケーションで新たに問題を引き起こす可能性があります。
マルチスレッド・アプリケーションのテストは、シングル・スレッド・アプリケーションのテストより難しい作業です。問題がタイミングに関連していることが多く、再現が困難だからです。
既存のコードでマルチスレッドとマルチコンテキストを使用するには、大部分のコードを再構築しなければなりません。プログラマは、以下の作業を行う必要があります。
|
•
|
スレッド・セーフではないすべての関数呼出しを置き換えます。
|
|
•
|
スレッド・セーフではないその他のコードを置き換えます。
|
移植が完了したら何度もテストを繰り返す必要があり、マルチスレッドおよびマルチコンテキスト・アプリケーションの移植には多くの作業が必要になります。
クライアントでのマルチスレッドとマルチコンテキストの動作
マルチスレッドおよびマルチコンテキスト・アプリケーションがアクティブの場合、クライアントのライフサイクルは次の3つのフェーズから構成されます。
|
•
|
一部のクライアント・スレッドは tpinit(3c)を呼び出して、1つ以上のOracle Tuxedoアプリケーションに参加します。
|
|
•
|
その他のクライアント・スレッドは tpsetctxt(3c)を呼び出して、最初のスレッド・セットによって生成されるコンテキストを共有します。
|
|
•
|
一部のクライアント・スレッドは複数のコンテキストに参加します。
|
|
•
|
一部のクライアント・スレッドは既存のコンテキストに切り替えます。
|
|
注意:
|
Oracle Tuxedoシステムから独立して動作するスレッドが存在する場合もあります。ここでは、そのようなスレッドについては説明していません。
|
Oracle Tuxedoマルチコンテキスト・アプリケーションのクライアントは、次の規則に従うかぎり、複数のアプリケーションに関連付けることができます。
|
•
|
すべての関連付けは、Oracle Tuxedoシステムの同じインストールに対して行う必要があります。
|
|
•
|
すべてのアプリケーションとの関連付けは、同じタイプのクライアントから行う必要があります。つまり、次のいずれかの条件を満たしている必要があります。
|
|
•
|
すべてのアプリケーションとの関連付けは、ネイティブ・クライアントから行う必要があります。
|
|
•
|
すべてのアプリケーションとの関連付けは、ワークステーション・クライアントから行う必要があります。
|
クライアントが複数のコンテキストに参加するには、
TPINFOデータ型の
flags要素に
TPMULTICONTEXTSフラグを設定して、
tpinit(3c)関数を呼び出します。
TPMULTICONTEXTSフラグを設定して
tpinit()関数が呼び出されると、アプリケーションとの新しい関連付けが生成され、スレッドに対するカレントの関連付けが指定されます。新しい関連付けが生成されるOracle Tuxedoドメインは、
TUXCONFIGまたは
WSENVFILE/WSNADDR環境変数の値で決定されます。
クライアント・スレッドの既存のコンテキストへの切り替わり
アプリケーション内でタスクの優先度が移り、ほかのOracle Tuxedoドメインと通信する必要が発生した場合、あるコンテキストから別のコンテキストにスレッドを再割り当てした方がよい場合があります。
このフェーズでは、各スレッドによって処理が行われます。次は、行われる処理の例です。
|
•
|
トランザクションの開始、コミット、またはロールバックを行います。
|
スレッドは、同期リクエストの場合は
tpcall(3c)、非同期リクエストの場合は
tpacall(3c)を呼び出して、サーバーにリクエストを送ります。
tpcall()でリクエストを送った場合、以降操作を行わなくても応答を受け取ることができます。
tpcall(3c)でサービスの非同期リクエストを送った場合、同じコンテキスト内のスレッドは
tpgetrply(3c)を呼び出して応答を受け取ります。このスレッドは、リクエストを送ったスレッドと同じスレッドではない場合もあります。
あるスレッドがトランザクションを開始すると、そのスレッドのコンテキストを共有するすべてのスレッドでそのトランザクションが共有されます。
コンテキスト内の多くのスレッドでトランザクションに関する処理が行われますが、トランザクションをコミットまたは中断できるのは1つのスレッドだけです。トランザクションをコミットまたは中断するスレッドは、トランザクションを開始したスレッドである必要はなく、トランザクションを処理しているどのスレッドでもかまいません。スレッド・アプリケーションでは、通常のトランザクション規則に従うために、適切に同期を行う必要があります。たとえば、未終了のRPC呼び出しや会話がある場合に、トランザクションをコミットすることはできません。また、トランザクションがコミットまたは中断された後で、そのトランザクションに対する呼出しを行うことはできません。プロセスは、アプリケーションの各関連付けに対して、1つのトランザクションの一部にだけなることができます。
アプリケーションの1つのスレッドが
tpcommit(3c)を呼び出し、それと同時に別のスレッドがRPC呼出しまたは会話型呼出しを行うと、これらの呼出しは特定の順序で呼び出されたものとして処理されます。アプリケーション・コンテキストは、シングル・スレッド・プログラムとシングル・コンテキスト・プログラムに対する制約と同じ制約に従って、
tpsuspend(3c)を呼び出してトランザクションを一時的に中断し、別のトランザクションを開始します。
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションの各コンテキストでは、非請求メッセージを次の3種類のいずれかの方法で処理できます。
|
|
|
|
|
|
|
|
|
専用のスレッド通知
(C言語のアプリケーションのみで利用可能です)
|
|
|
•
|
シグナル・ベースの通知は、マルチスレッド・プロセスまたはマルチコンテキスト・プロセスでは使用できません。
|
|
•
|
アプリケーションを実行しているプラットフォームで、マルチコンテキストがサポートされていてもマルチスレッドがサポートされていない場合、 TPU_THREADを使用した非請求通知の処理を行うことはできません。そのため、イベントの即時通知を受け取ることはできません。
|
イベントの即時通知を受け取る必要がある場合は、そのプラットフォームでマルチコンテキストを使用するかどうかを慎重に検討します。
|
•
|
専用のスレッド通知は、次のものに対してだけ使用できます。
|
|
•
|
Oracle Tuxedoシステムでサポートされているマルチスレッド・プラットフォーム
|
専用のスレッド通知の場合、非請求メッセージの受信と、非請求メッセージ・ハンドラのディスパッチに別々のスレッドが使用されます。あるコンテキストで一度に実行できる非請求メッセージ・ハンドラは1つだけです。
スレッドがサポートされていないOracle Tuxedoシステム用プラットフォームで
tpinit(3c)が呼び出された場合に、スレッドがサポートされていないプラットフォーム上で
TPU_THREAD通知がリクエストされたことを示すパラメータが指定されていると、
tpinit()は
-1を返して
tperrnoを
TPEINVALに設定します。
UBBCONFIG(5)のデフォルトの
NOTIFYオプションが
THREADに設定されている場合に、特定のマシンでスレッドを使用できないと、そのマシンのデフォルトの機能は
DIPINになります。このような動作の相違があるので、スレッドがサポートされているマシンとサポートされていないマシンが混在する環境では、管理者はすべてのマシンにデフォルトを指定できます。ただし、そのマシンで利用できない機能をクライアントが明示的にリクエストすることはできません。
tpsetunsol(3c)がコンテキストに関連付けされていないスレッドから呼び出されると、新しく生成されるすべての
tpinit(3c)コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ・ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに
tpsetunsol()を再度呼び出して、そのコンテキストの非請求メッセージ・ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ・ハンドラは、コンテキストに現在関連付けされていないスレッドで
tpsetunsol()を再度呼び出すと、変更できます。
プロセスが同じアプリケーションと複数の関連付けを持つ場合、各関連付けに異なる
CLIENTIDを割り当てられ、非請求メッセージを特定のアプリケーションとの関連付けに送信できるようになります。プロセスが同じアプリケーションと複数の関連付けを持つ場合、ブロードキャスト基準を満たすアプリケーションの各関連付けに任意の
tpbroadcast(3c)が別々に送信されます。非請求メッセージを受信する場合のディップ・イン・チェックでは、カレントのアプリケーションとの関連付けに送信されるメッセージだけが対象となります。
非請求メッセージ・ハンドラではATMI関数を利用できる他、非請求メッセージ・ハンドラ内で
tpgetctxt(3c)を呼び出すことができます。そのため、非請求メッセージ・ハンドラは別のスレッドを生成して、同じコンテキスト内で必要となる実質的なATMI作業を行うことができるようになります。
process_ID.
thread_ID.
context_ID
スレッドがサポートされていないプラットフォームやシングル・コンテキスト・アプリケーションに対しては、エントリの
thread_IDフィールドと
context_IDフィールドにプレースホルダーが出力されます。
TM_MIB(5)では、この機能は
T_ULOGクラスの
TA_THREADIDフィールドと
TA_CONTEXTIDフィールドでサポートされています。
このフェーズでは、クライアント・プロセスの終了時に、現在のコンテキストおよび関連付けられたすべてのスレッドにかわって1つのスレッドが
tpterm(3c)を呼び出してそのアプリケーションとの関連付けを終了します。ほかのATMI関数と同じように、
tpterm()は現在のコンテキストに対して処理を行います。それは、終了するコンテキストに対応付けされたすべてのスレッドに影響し、これらのスレッドで共有されるすべてのコンテキストを終了します。
アプリケーションの設計が適切であれば、特定のコンテキスト内のすべての処理が完了してから
tpterm()が呼び出されます。
tpterm()が呼び出される前に、すべてのスレッドが同期していなければなりません。
ATMIサーバーでのマルチスレッドとマルチコンテキストの動作
マルチスレッドおよびマルチコンテキスト・アプリケーションがアクティブの場合、ATMIサーバーで行われる処理は次の3つのフェーズに分類できます。
起動フェーズで行われる処理は、構成ファイルの
MINDISPATCHTHREADSと
MAXDISPATCHTHREADSパラメータの値によって異なります。
|
|
|
|
|
|
|
|
1.
|
Oracle Tuxedoシステムがスレッド・ディスパッチャを生成します。
|
|
|
|
|
|
1.
|
Oracle Tuxedoシステムがスレッド・ディスパッチャを生成します。
|
|
3.
|
Oracle Tuxedoシステムがサービス・リクエストを処理する新しいスレッドと、そのスレッドに対するコンテキストを生成します。
|
|
|
•
|
1つのサーバーに対する複数のクライアント・リクエストが、複数のコンテキストで同時に処理されます。リクエストごとに別のスレッドが割り当てられます。
|
|
•
|
必要に応じて、 MAXDISPATCHTHREADSで指定された値まで新しいスレッドが生成されます。
|
|
•
|
サーバー・スレッドの統計がシステムで保持されます。
|
クライアントのサービス・リクエストへのレスポンスとして、サーバー・ディスパッチャは各種のクライアント・リクエストに同時に割り当てることができる1つのサーバーに、設定可能な最大数まで複数のスレッドを生成します。サーバーが
tpinit(3c)を呼び出してクライアントになることはできません。
各ディスパッチ・スレッドは、別々のコンテキストと関連付けられています。この機能は会話型サーバーとRPCサーバーで有用です。特に、会話型サーバーではこの機能を利用できないと、ほかの会話接続がサービスを待っている間、クライアント側の会話をアイドル状態で待つことになります。
|
•
|
各ディスパッチ・スレッドは、 THREADSTACKSIZEまたは TA_THREADSTACKSIZEで指定されるスタック・サイズで生成されます。このパラメータが指定されていない場合、または0の場合、オペレーティング・システムのデフォルト値が使用されます。オペレーティング・システムのデフォルト値が小さすぎてOracle Tuxedoシステムで使用できない場合、その値より大きなデフォルト値が使用されます。
|
|
•
|
このパラメータが指定されていない(0)の場合、あるいはオペレーティング・システムで THREADSTACKSIZE設定がサポートされていない場合は、オペレーティング・システムのデフォルト値が使用されます。
|
|
•
|
MINDISPATCHTHREADSまたは TA_MINDISPATCHTHREADSは、 MAXDISPATCHTHREADSまたは TA_MAXDISPATCHTHREADS以下でなければなりません。
|
|
•
|
MAXDISPATCHTHREADSまたは TA_MAXDISPATCHTHREADSが1の場合、ディスパッチャ・スレッドとサービス関数スレッドは同じスレッドです。
|
|
•
|
MAXDISPATCHTHREADSまたは TA_MAXDISPATCHTHREADSが1より大きい場合、ほかのスレッドのディスパッチに使用されるスレッドは、ディスパッチ・スレッドとしてカウントされません。
|
|
•
|
システムは最初に MINDISPATCHTHREADSまたは TA_MINDISPATCHTHREADSのサーバー・スレッドを起動します。
|
|
•
|
システムが MAXDISPATCHTHREADSまたは TA_MAXDISPATCHTHREADSを超えるサーバー・スレッドを起動することはありません。
|
オペレーティング・システム関数を使用して、アプリケーション・サーバー内に新しいスレッドを追加できます。アプリケーション生成のスレッドは、次のように動作します。
|
•
|
Oracle Tuxedoシステムから独立して動作します。
|
|
•
|
既存のサーバー・ディスパッチ・スレッドと同じコンテキストで動作します。
|
|
•
|
サーバー・ディスパッチ・コンテキストにかわって作業を行います。
|
アプリケーション内にスレッドを生成する場合、次の制約があります。
|
•
|
最初、アプリケーション生成サーバー・スレッドは、どのサーバー・ディスパッチ・コンテキストにも関連していません。アプリケーション生成のサーバー・スレッドは tpsetctxt(3c)を呼び出し、サーバー・ディスパッチ・スレッド内の以前の tpgetctxt(3c)呼出しによって返される値を渡して、サーバー・ディスパッチ・コンテキストとの関連付けを確立します。
|
BBLは定期的にサーバーを検証します。特定のサービス・リクエストの実行に時間がかかりすぎている場合、BBLはそのサーバーを強制終了します。(そして、指定されている場合は、そのサーバーを再起動します。)BBLがマルチコンテキスト・サーバーを強制終了した場合、プロセスを強制終了した結果として、実行中のそのほかのサービス呼び出しも終了します。
また、BBLはタイムアウト値を超えてメッセージの受信を待機しているプロセスまたはスレッドにメッセージを送信します。すると、ブロッキング・メッセージ受信への呼出しが、タイムアウトを示すエラーを返します。
Oracle Tuxedoシステムでは、各サーバーに対して次の統計情報が保持されます。
|
•
|
使用できるサーバー・ディスパッチ・スレッドの最大数
|
|
•
|
現在使用中のサーバー・ディスパッチ・スレッドの数( TA_CURDISPATCHTHREADS)
|
|
•
|
サーバー起動後の同時実行サーバー・ディスパッチ・スレッドの最大数( TA_HWDISPATCHTHREADS)
|
|
•
|
これまでに起動したサーバー・ディスパッチ・スレッドの数( TA_NUMDISPATCHTHREADS)
|
process_ID.
thread_ID.
context_ID
スレッドがサポートされていないプラットフォームやシングル・コンテキスト・アプリケーションに対しては、エントリの
thread_IDフィールドと
context_IDフィールドにプレースホルダーが出力されます。
TM_MIB(5)では、この機能は
T_ULOGクラスの
TA_THREADIDフィールドと
TA_CONTEXTIDフィールドでサポートされています。
マルチスレッドおよびマルチコンテキストATMIアプリケーションの設計上の検討事項
マルチスレッドおよびマルチコンテキストATMIアプリケーションは、一部のOracle Tuxedoドメインでは正しく動作しますが、すべてのドメインで正しく動作するとはかぎりません。そのようなアプリケーションを作成するかどうかは、次の基本事項を検討してから決定します。
|
•
|
ワークステーション・クライアントに対する相互運用性での制約
|
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションの開発では、開発環境と実行時環境に関して次の内容を検討します。
|
•
|
十分な経験を持つプログラマ・チームがあり、同時実行性と同期を正しく管理するマルチスレッドおよびマルチコンテキスト・プログラムのコーディングとデバッグを行うことができるかどうか。
|
|
•
|
アプリケーションを開発するプラットフォームで、Oracle Tuxedoシステムのマルチスレッド機能がサポートされているかどうか。マルチスレッド機能は、オペレーティング・システムで提供されるスレッド・パッケージがインストールされ、適切なレベルの機能性が提供されたプラットフォームだけでサポートされます。
|
|
•
|
サーバーで使用されるリソース・マネージャ(RM)でマルチスレッドがサポートされているかどうか。サポートされている場合は、次の内容も検討します。
|
|
•
|
サーバーでマルチスレッド・アクセスを使用するためにRMに必要なパラメータを設定する必要があるかどうか。たとえば、マルチスレッド・アプリケーションでOracleデータベースを使用する場合、Oracleに渡される OPENINFO文字列の一部として THREADS=trueパラメータを設定する必要があります。この設定により、各スレッドがOracleとの別々の関連付けとして動作するようになります。
|
|
•
|
RMで処理の混在モードがサポートされているかどうか。処理の混在モードは、あるプロセスの複数のスレッドが、1つのRMとの関連付けにマップでき、また同じプロセスのほかのスレッドが別のRMとの関連付けにマップできるアクセス方法です。たとえば、1つのプロセス内でスレッドAとBがRMとの関連付けXにマップし、同時にスレッドCがRMとの関連付けYにマップできます。
|
すべてのRMで混在モードがサポートされているわけではありません。プロセス内のすべてのスレッドが同じRMとの関連付けにマップされなければならない場合もあります。アプリケーション生成のスレッド内でトランザクションに関与するRMアクセスを使用するアプリケーションを設計する場合は、RMで混在モードがサポートされていることを確認します。
マルチスレッド・アプリケーションやマルチコンテキスト・アプリケーションの設計では、次の内容を検討します。
|
•
|
アプリケーションによって実行されるタスクが、マルチスレッドやマルチコンテキストに適しているかどうか。
|
|
•
|
複数のOracle Tuxedoアプリケーションに接続するかどうか。各ターゲット・アプリケーションに必要な接続数はいくつか。
|
|
•
|
アプリケーションで考慮すべき同期に関する検討事項は何か。
|
|
•
|
初期アプリケーションの完成後、アプリケーションを別のプラットフォームに移植する必要があるかどうか。
|
マルチスレッドやマルチコンテキストに適するアプリケーションのタスク
次の表は、アプリケーションをマルチスレッドまたはマルチコンテキストにすべきかどうかを判断するための参考となる検討事項を示しています。この表だけでは十分ではないので、個々の要件に基づいてほかの事項も検討してください。
そのほかの検討事項については、マルチスレッド・アプリケーションやマルチコンテキスト・アプリケーションのプログラミングに関する書籍を参照してください。
|
|
|
ドメイン機能を使用せずに、クライアントが複数のアプリケーションに接続する必要があるか
|
|
アプリケーション内でクライアントが多重化の機能を果たすか。たとえば、アプリケーション内の1つのマシンがそのほかの100台のマシンの「代理」に指定されているか
|
|
|
|
マルチスレッド。各コンテキストにスレッドを1つずつ割り当てると、コードを簡略化できます。
|
クライアントが2つ以上のタスクを長時間個別に実行することで、並列処理によるパフォーマンスがスレッド同期のコストと複雑さを上回るか
|
|
1つのサーバーで複数のリクエストを同時に処理するか
|
マルチスレッド。 MAXDISPATCHTHREADSに1より大きな値を割り当てます。このように設定すると、1つのサーバーで複数のクライアントをそのクライアントのスレッドで処理できるようになります。
|
クライアントまたはサーバーに複数のスレッドがある場合、各スレッドでわずかな処理を行った後でもスレッドを同期する必要があるか
|
|
アクセスするアプリケーションの数と、確立する接続の数を決定します。
|
•
|
複数のアプリケーションに接続する場合は、次のいずれかを使用します。
|
|
•
|
シングル・スレッドおよびマルチコンテキスト・アプリケーション
|
|
•
|
マルチスレッドおよびマルチコンテキスト・アプリケーション
|
|
•
|
1つのアプリケーションに複数の接続を確立する場合は、マルチスレッドおよびマルチコンテキスト・アプリケーションを使用します。
|
|
•
|
1つのアプリケーションに1つだけ接続を確立する場合は、次のいずれかを使用します。
|
|
•
|
マルチスレッドおよびシングル・コンテキスト・クライアント
|
|
•
|
シングル・スレッドおよびシングル・コンテキスト・クライアント
|
いずれの場合も、マルチスレッドおよびマルチコンテキスト・サーバーを使用できます。
これは設計段階での重要な検討事項です。このドキュメントでは、この内容について取り上げていません。マルチスレッド・アプリケーションやマルチコンテキスト・アプリケーションのプログラミングに関する書籍を参照してください。
後でアプリケーションを移植する必要がある場合、オペレーティング・システムに応じて異なる関数が使用されていることに注目してください。あるプラットフォームで作成した初期バージョンのアプリケーションを後で移植する場合、異なる関数でコードを書き直すためにどれだけのリソース時間が必要なのかを考慮する必要があります。
現在使用されているマルチスレッド・プログラムには、次のようなモデルがあります。
スレッド・モデルについては、このドキュメントでは取り上げていません。アプリケーションのプログラミング・モデルを選択する場合は、利用できるすべてのモデルを調べて、設計の要件を慎重に検討してください。
ワークステーション・クライアントの相互運用性に関する制約
リリース7.1のWorkstationクライアントと7.1以前のOracle Tuxedoシステムに基づくアプリケーションとの相互運用性は、次のどの場合でもサポートされています。
|
•
|
マルチスレッド化またはマルチコンテキスト化されたクライアントではありません。
|
|
•
|
クライアントがマルチスレッド化されており、各スレッドが異なるコンテキストにあります。
|
Oracle Tuxedoリリース7.1のワークステーション・クライアントで、1つのコンテキストに複数のスレッドがある場合は、リリース7.1より前のOracle Tuxedoシステムとは相互運用しません。
マルチスレッドおよびマルチコンテキストATMIアプリケーションの実装
マルチスレッド/マルチコンテキストATMIアプリケーションのプログラミング開始前のガイドライン
コーディングを開始する前に、次の内容や条件を満たしていることを確認してください。
マルチスレッドATMIアプリケーションに必要な条件
開発プロジェクトを開始する前に、開発環境が次の条件を満たしていることを確認します。
|
•
|
Oracle Tuxedoシステムでサポートされる適切なスレッド・パッケージが、オペレーティング・システムで提供されていることが必要です。
|
Oracle Tuxedoシステムには、スレッド生成用のツールは提供されていませんが、他のオペレーティング・システムで提供される各種のスレッド・パッケージがサポートされています。スレッドを生成して同期するには、オペレーティング・システム固有の関数を使用する必要があります。オペレーティング・システムでサポートされているスレッド・パッケージを確認するには、
『Oracle Tuxedoシステムのインストール』を参照してください。
|
•
|
マルチスレッド・サーバーを使用している場合は、これらのサーバーで使用されるリソース・マネージャでスレッドがサポートされていることが必要です。
|
マルチスレッド・アプリケーションのプログラミングでの一般的な検討事項
マルチスレッド・プログラムは、十分に経験を持つプログラマがコーディングします。特に、次のようなマルチスレッド固有の設計に関する基本的な知識があることが必要です。
|
•
|
ほどんどのインスタンスで静的変数の使用を避ける必要性
|
|
•
|
マルチスレッド・プログラムでシグナルを使用することにより発生する可能性のある問題
|
これらは検討事項の一部にすぎず、ここに記せないほど多くの検討事項があります。マルチスレッド・プログラムをコーディングするプログラマは、それらの検討事項を熟知していることが前提となります。これらの検討事項については、マルチスレッド・アプリケーションのプログラミングに関する書籍を参照してください。
マルチスレッドを使用すると、1つのアプリケーションの異なるスレッドが同じ会話で並列処理を行うことができるようになります。この方法はお薦めしませんが、Oracle Tuxedoシステムで禁止されているわけではありません。異なるスレッドによって同じ会話で並列処理が行われると、システムは同時呼出しが任意の順序で行われたように動作します。
複数のスレッドを使ってプログラミングする場合、ミューテックスなどの同時実行性制御関数を使用して、スレッド間の並列処理を管理する必要があります。以下は、同時実行性制御が必要になる3つの例です。
|
•
|
マルチスレッドのスレッドが同じコンテキストで動作する場合、プログラマは関数が必要な順序で実行されるようにします。たとえば、すべてのRPC呼出しと会話が完了した後でのみ、 tpcommit(3c)を呼び出せるようにします。これらすべてのRPC呼び出しまたは会話型呼出しが行われるスレッドとは別のスレッドから tpcommit()が呼び出される場合、アプリケーションで何らかの同時実行性制御が必要になります。
|
|
•
|
tpacall()が呼び出された後で tpgetrply()が呼び出されます。
|
|
•
|
tpacall()を呼び出す前に tpgetrply()が呼び出される場合、結果が管理されます。
|
|
•
|
複数のスレッドが同じ会話で処理を行うことは可能です。ただし、異なるスレッドが tpsend(3c)をほとんど同時に呼び出した場合、システムはそれらの tpsend()呼出しが任意の順序で行われたように動作します。アプリケーション・プログラマは、それを認識しておく必要があります。
|
ほとんどのアプリケーションで最良の戦略は、1つの会話のすべての処理を1つのスレッドにまとめてコーディングすることです。次善の戦略は、同時実行性制御を使用して、これらの処理を連続して行うことです。
ATMIクライアントでマルチコンテキストを使用するためのコーディング
クライアントでマルチコンテキストを使用するには、次の内容をコーディングします。
|
•
|
マルチスレッドも使用する場合は、スレッドを同期します。
|
|
注意:
|
この項で示す手順とサンプル・コードは、Oracle Tuxedoシステムで提供されるC言語のライブラリ関数を参照します。それらに相当するCOBOLライブラリ関数も利用できます。詳細については、 『Oracle Tuxedo COBOL関数リファレンス』を参照してください。
|
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
|
•
|
プロセス内のすべてのコンテキストに、同じバッファ・タイプ・スイッチを使用します。
|
|
•
|
ほかのタイプのデータ構造体と同じように、マルチスレッド・アプリケーションではOracle Tuxedoバッファを適切に使用する必要があります。つまり、次のいずれかが該当する場合、バッファを2つの呼出しで同時に使用することはできません。
|
|
•
|
1つの呼出しでバッファを使用し、もう1つの呼出しでバッファを解放する場合
|
|
•
|
tpinit(3c)を複数回呼び出して、複数アプリケーションに参加するか、または単一アプリケーションに複数の接続を行う場合、 tpinit()を呼び出すたびに、確立されているセキュリティ・メカニズムを調整する必要があります。
|
クライアントがアプリケーションに参加する準備ができたら、次のサンプル・コードに示すように、
TPMULTICONTEXTSフラグを設定して
tpiit(3c)を指定します。
リスト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(3c)へのすべての呼出しに TPMULTICONTEXTSフラグを含めるか、または、 tpinit()へのすべての呼出しにこのフラグを含めません。この規則には例外が1つあり、 tpterm(3c)への呼出しが正常に終了して、クライアントのすべてのアプリケーション関連付けが終了した場合、次に tpinit()を呼び出すときに必ずしも TPMULTICONTEXTSフラグを含む必要のない状態にプロセスが復元されます。
|
マルチコンテキストATMIクライアントのセキュリティの実装
同じプロセス内の各アプリケーションとの関連付けには、別個にセキュリティ検証を行う必要があります。検証の内容は、アプリケーションで使用されているセキュリティ・メカニズムのタイプによって異なります。たとえば、Oracle Tuxedoアプリケーションでは、システム・レベルのパスワードまたはアプリケーション・パスワードを使用します。
マルチコンテキスト・アプリケーションのプログラマは、アプリケーションで使用するセキュリティのタイプを決定し、そのセキュリティをプロセス内の各アプリケーションとの関連付けに実装します。
クライアントをアプリケーションから切断する準備ができたら、
tpterm(3c)を呼び出します。ただし、マルチコンテキスト・アプリケーションでは、
tpterm()を呼び出すと現在のコンテキストが破棄されることに注目してください。その場合、現在のコンテキストで動作しているすべてのスレッドが影響を受けます。アプリケーション・プログラマは、
tpterm()が不意に呼び出されることがないように、複数のスレッドを使用する場合は注意してください。
まだ処理を行っているスレッドがあるコンテキストでは、
tpterm(3c)を呼び出さないようにします。そのような状況で
tpterm()を呼び出すと、そのコンテキストと関連付けられていたほかのスレッドが特別な無効コンテキスト状態になります。無効コンテキスト状態では、大部分のATMI関数を使用できなくなります。無効コンテキスト状態からスレッドを解放するには、
tpsetctxt(3c)または
tpterm()を呼び出します。良く設計されたアプリケーションでは、無効コンテキスト状態が生じることはありません。
|
注意:
|
Oracle Tuxedoシステムでは、COBOLアプリケーションのマルチスレッドはサポートされていません。
|
次は、2つのコンテキストからサービスを呼び出すクライアントで行われる処理の手順をまとめたものです。
|
1.
|
TUXCONFIG環境変数に firstappで必要な値を設定します。
|
|
2.
|
TPMULTICONTEXTSフラグを設定して tpinit(3c)を呼び出し、最初のアプリケーションに参加します。
|
|
4.
|
tuxputenv()を呼び出して、 TUXCONFIG環境変数の値を secondappコンテキストに必要な値に切り替えます。
|
|
5.
|
TPMULTICONTEXTSフラグを設定して tpinit(3c)を呼び出して、2番目のアプリケーションに参加します。
|
|
9.
|
tpsetctxt(3c)を呼び出してクライアントを secondappコンテキストに切り替え、 secondappサービスを呼び出します。
|
|
10.
|
tpsetctxt(3c)を呼び出してクライアントを firstappコンテキストに切り替え、 firstappサービスを呼び出します。
|
|
12.
|
tpsetctxt(3c)を呼び出してクライアントを secondappコンテキストに切り替え、 secondappサービスを呼び出します。
|
|
注意:
|
コードを簡単にするために、エラー・チェックは省略してあります。
|
リスト10-2
クライアントでのコンテキストの切替え
#include <stdio.h>
#include "atmi.h" /* BEA Tuxedo header file */
#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;
/* Assume that TUXCONFIG is initially set to /home/firstapp/TUXCONFIG*/
/*
* Attach to the BEA Tuxedo system in multicontext mode.
*/
tpinitbuf=tpalloc(TPINIT, NULL, TPINITNEED(0));
tpinitbuf->flags = TPMULTICONTEXTS;
if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}
/*
* Obtain a handle to the current context.
*/
tpgetctxt(&firstapp_contextID, 0);
/*
* Use tuxputenv to change the value of TUXCONFIG,
* so we now tpinit to another application.
*/
tuxputenv("TUXCONFIG=/home/second_app/TUXCONFIG");
/*
* tpinit to secondapp.
*/
if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}
/*
* Get a handle to the context of secondapp.
*/
tpgetctxt(&secondapp_contextID, 0);
/*
* Now you can alternate between the two contexts
* using tpsetctxt and the handles you obtained from
* tpgetctxt. You begin with firstapp.
*/
tpsetctxt(firstapp_contextID, 0);
/*
* You call services offered by firstapp and then switch
* to secondapp.
*/
tpsetctxt(secondapp_contextID, 0);
/*
* You call services offered by secondapp.
* Then you switch back to firstapp.
*/
tpsetctxt(firstapp_contextID, 0);
/*
* You call services offered by firstapp. When you have
* finished, you terminate the context for firstapp.
*/
tpterm();
/*
* Then you switch back to secondapp.
*/
tpsetctxt(secondapp_contextID, 0);
/*
* You call services offered by secondapp. When you have
finished, you terminate the context for secondapp and
end your program.
*/
tpterm();
return(0);
}
非請求メッセージを処理する各コンテキストでは、非請求メッセージ・ハンドラを設定するか、またはプロセス・ハンドラのデフォルトが設定されている場合はそれを使用する必要があります。
tpsetunsol(3c)がコンテキストに関連付けされていないスレッドから呼び出されると、新しく生成されるすべての
tpinit(3c)コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ・ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに
tpsetunsol()を再度呼び出して、そのコンテキストの非請求メッセージ・ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ・ハンドラは、コンテキストに現在関連付けされていないスレッドで
tpsetunsol()を再度呼び出すと、変更できます。
ハンドラの設定は、シングル・スレッド・アプリケーションまたはシングル・コンテキスト・アプリケーションのハンドラを設定する場合と同じように行います。詳細は、
「tpsetunsol(3c)」を参照してください。
マルチスレッド/マルチコンテキストATMIアプリケーションにおけるトランザクションのコーディング規則
トランザクションを使用する場合、コーディングで以下の事柄に注意してください。
|
•
|
1つのコンテキストで所有できるトランザクションは1つだけです。
|
|
•
|
各コンテキストで異なるトランザクションを使用できます。
|
|
•
|
ある時点で任意のコンテキストに関連付けされているすべてのスレッドは、そのコンテキストの同じトランザクション状態を共有します。
|
ATMIサーバーでマルチコンテキストとマルチスレッドを使用するためのコーディング
|
注意:
|
この項で示す手順とサンプル・コードは、Oracle Tuxedoシステムで提供されるC言語のライブラリ関数を参照します。(詳細は、 『Oracle Tuxedo C関数リファレンス』を参照してください。)COBOLアプリケーションではマルチコンテキスト・サーバーの生成に必要なマルチスレッドがサポートされていないので、C言語の関数に相当するCOBOLルーチンは利用できません。
|
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
|
•
|
プロセス内のすべてのコンテキストに、同じバッファ・タイプ・スイッチを使用します。
|
|
•
|
ほかのタイプのデータ構造体と同じように、マルチスレッド・アプリケーションではOracle Tuxedoバッファを適切に使用する必要があります。つまり、次のいずれかが該当する場合、バッファを2つの呼出しで同時に使用することはできません。
|
|
•
|
1つの呼出しでバッファを使用し、もう1つの呼出しでバッファを解放する場合
|
マルチコンテキストATMIサーバーのコーディング規則
マルチコンテキスト・サーバー使用する場合、コーディングで以下の規則に注意してください。
|
•
|
サーバー上のOracle Tuxedoディスパッチャは、同じサービスまたは異なるサービスを複数回ディスパッチでき、ディスパッチされるサービスごとに異なるディスパッチ・コンテキストを生成します。
|
|
•
|
サーバーは、 tpinit(3c)を呼び出したり、クライアントとして動作することはできません。サーバー・プロセスで tpinit()が呼び出されると、 tpinit()は -1を返して tperrno(5)を TPEPROTOに設定します。アプリケーション生成のサーバー・スレッドは、 tpsetctxt(3c)を呼び出す前にATMIを呼び出すことはできません。
|
|
•
|
アプリケーション生成のスレッドが任意のアプリケーションのコンテキストに関連付けされている場合、サーバーは tpreturn(3c)または tpforward(3c)を実行できません。そのため、サーバー・ディスパッチ・スレッドが tpreturn()を呼び出す前に、そのコンテキストに対応するアプリケーション生成の各スレッドがコンテキストを TPNULLCONTEXTまたは別の有効なコンテキストに設定して tpsetctxt(3c)を呼び出す必要があります。
|
この規則に違反すると、
tpreturn(3c)または
tpforward(3c)はユーザー・ログにメッセージを書き込み、呼出し側に
TPESVCERRを示して、メイン・サーバーのディスパッチ・ループに制御を戻します。無効
tpreturn()が実行されたコンテキスト内のスレッドは、無効コンテキスト状態になります。
|
•
|
tpreturn(3c)または tpforward(3c)が呼び出されたときに未終了のATMI呼出し、RPC呼出しまたは会話が存在する場合は、 tpreturn()または tpforward()はユーザー・ログにメッセージを書き込み、呼出し側に TPESVCERRを知らせて、メイン・サーバーのディスパッチ・ループに制御を戻します。
|
|
•
|
シングル・コンテキストのサーバーとは異なり、マルチコンテキスト・サーバー・スレッドでは、同じサーバー・プロセスだけで提供されるサービスを呼び出すことができます。
|
ATMIサーバーおよびATMIサーバー・スレッドの初期化と終了
サーバーとサーバー・スレッドの初期化と終了には、Oracle Tuxedoシステムで提供されるデフォルトの関数や独自の関数を使用できます。
スレッドを生成するためのATMIサーバーのプログラミング
マルチコンテキスト・サーバーを使用するほとんどのアプリケーションでは、システム生成のディスパッチ・サーバー・スレッドだけが使用されます。ただし、アプリケーション・サーバーに新しいスレッドを生成することもできます。この節では、その方法について説明します。
オペレーティング・システムのスレッド関数を使用して、アプリケーション・サーバーに新しいスレッドを生成できます。これらの新しいスレッドは、Oracle Tuxedoシステムから独立して動作できます。また、いずれかのサーバー・ディスパッチ・スレッドと同じコンテキストで動作することもできます。
アプリケーション生成のサーバー・スレッドは、当初どのサーバー・ディスパッチ・コンテキストにも関連付けられていません。ただし、初期化される前に呼び出された場合、ほとんどのATMI関数は暗黙的に
tpinit(3c)を実行します。サーバーで
tpinit()を呼び出すことは禁止されているので、そのような呼出しを行うと問題が発生します。(サーバー・プロセスで
tpinit()が呼び出されると、
tpinit()は-1を返して
tperrno(5)に
TPEPROTOを設定します。)
そのため、アプリケーション生成のサーバー・スレッドは、既存のコンテキストと関連付けを行ってからATMI関数を呼び出す必要があります。アプリケーション生成のサーバー・スレッドを既存のコンテキストに関連付けるには、以下の手順をコーディングします。
|
3.
|
アプリケーション・スレッド_Bは、 tpsetctxt(3c)を呼び出してサーバー・ディスパッチ・スレッド_Aから受け取ったハンドルを指定して、現在のコンテキストとの関連付けを作成します。
|
|
4.
|
アプリケーション生成のサーバー・スレッドは、 tpreturn(3c)または tpforward(3c)を呼び出すことはできません。元のディスパッチ・スレッドが tpreturn()または tpforward()を呼び出す前に、そのコンテキストにあったすべてのアプリケーション生成のサーバー・スレッドは TPNULLCONTEXTまたは別の有効なコンテキストに切り替える必要があります。
|
マルチコンテキストATMIサーバーでアプリケーション・スレッドを生成するためのサンプル・コード
次のサンプル・コードは、サービスが別のスレッドを生成してそのサービスの作業を行うマルチコンテキスト・サーバーを示しています。オペレーティング・システムのスレッド関数は、オペレーティング・システムによって異なります。このサンプル・コードでは、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();
return(NULL);
}
このコードでは、元のディスパッチ・スレッドで
DEPOSITサービスを呼び出し、アプリケーション生成のスレッドで
WITHDRAWALを呼び出して、口座振替えを行っています。この例では、リソース・マネージャで混在モデルがサポートされていることを前提としています。つまり、サーバーのすべてのスレッドが特定のインスタンスと関連付けされていなくても、そのサーバーの複数のスレッドが特定のデータベース接続と関連付けられます。ただし、そのようなモデルがサポートされたリソース・マネージャはほとんどありません。
|
注意:
|
Oracle Tuxedoシステムでは、COBOLアプリケーションのマルチスレッドはサポートされていません。
|
マルチスレッドATMIクライアントのコーディング規則
マルチスレッド・クライアントを使用する場合、コーディングで以下の規則に注意してください。
|
•
|
会話が開始されると、同じプロセス内のすべてのスレッドでその会話を操作できます。ハンドルと呼出し記述子は、同じプロセスの同じコンテキスト内で移植できます。ただし、ほかのコンテキストやプロセスには移植できません。ハンドルと呼出し記述子は、それらが元々割り当てられていたアプリケーション・コンテキストだけで使用できます。
|
|
•
|
トランザクションをコミットまたは中断できるのは、1つのスレッドだけです。トランザクションを開始したスレッドである必要はありません。
|
|
•
|
すべてのRPC呼出しと会話は、トランザクションをコミットする前に完了していなければなりません。未終了のRPC呼出しや会話があるときに tpcommit(3c)が呼び出されると、 tpcommit()はトランザクションを中断し、 -1を返して tperrno(5)を TPEABORTに設定します。
|
|
•
|
クライアントを使用している場合に複数のドメインに接続するときは、 TUXCONFIGまたは WSNADDRの値を手動で変更してから tpinit(3c)を呼び出します。このような処理が複数のスレッドで行われる場合、環境変数の設定と tpinit()呼出しを同期する必要があります。クライアントのすべてのアプリケーション関連付けは、以下の規則に従う必要があります。
|
|
•
|
すべての関連付けは、同じリリースのOracle Tuxedoシステムに対して行われます。
|
|
•
|
特定のクライアントのすべてのアプリケーション関連付けはネイティブ・クライアントとして生成するか、またはワークステーション・クライアントとして生成します。
|
|
•
|
アプリケーションに参加するには、マルチスレッドのワークステーション・クライアントが、シングル・コンテキスト・モードで実行している場合でも、常に TPMULTICONTEXTSフラグを設定して tpinit(3c)を呼び出す必要があります。
|
ATMIクライアントの複数のコンテキストへの初期化
クライアントを複数のコンテキストに参加させるには、
TPINITデータ構造体の
flags要素に
TPMULTICONTEXTSフラグを設定して
tpinit(3c)関数を呼び出します。
1つのプロセスでは、
tpinit(3c)へのすべての呼出しに
TPMULTICONTEXTSフラグを含めるか、または、
tpinit()へのすべての呼出しにこのフラグを含めません。この規則には例外が1つあり、
tpterm(3c)への呼出しが正常に終了して、クライアントのすべてのアプリケーション関連付けが終了した場合、次に
tpinit()を呼び出すときに必ずしも
TPMULTICONTEXTSフラグを含む必要のない状態にプロセスが復元されます。
TPMULTICONTEXTSフラグを設定して
tpinit(3c)が呼び出されると、アプリケーションとの新しい関連付けが生成され、スレッドに対するカレントの関連付けが設定されます。新しい関連付けが生成されるOracle Tuxedoドメインは、
TUXCONFIGまたは
WSENVFILE/WSNADDR環境変数の値で決定されます。
クライアント・スレッドが
TPMULTICONTEXTSフラグを設定せずに
tpinit(3c)を正常に実行した場合、クライアントのすべてのスレッドがシングル・コンテキスト状態(
TPSINGLECONTEXT)になります。
tpinit(3c)が失敗した場合、呼出し側スレッドは元のコンテキスト、つまり
tpinit()呼出しの前に操作していたコンテキスト状態のままになります。
ATMIクライアント・スレッドのコンテキスト状態の変化
|
注意:
|
tpterm(3c)がマルチコンテキスト状態( TPMULTICONTEXTS)で実行しているスレッドによって呼び出されると、呼出し側スレッドはNULLコンテキスト状態( TPNULLCONTEXT)になります。終了するコンテキストに関連するその他すべてのスレッドは、無効コンテキスト状態( TPINVALIDCONTEXT)に切り替わります。
|
tpgetrply(3c)は、1つのコンテキスト、つまり呼出し側コンテキストのみで動作します。そのため、
TPGETANYフラグを設定して
tpgetrply()を呼び出すと、同じコンテキストで生成されたハンドルだけが考慮されます。同じように、あるコンテキストで生成されたハンドルを別のコンテキストで使用することはできません。ただし、同じコンテキストで動作するスレッドには、そのハンドルを使用できます。
|
•
|
1つのスレッドがすでに tpgetrply()で特定のハンドルを待機しているときに、同じコンテキストの別のスレッドが tpgetrply(3c)を呼び出して同じハンドルの取得を試みると、 tpgetrply()は -1を返して tperrnoを TPEPROTOに設定します。
|
|
•
|
1つのスレッドがすでに TPGETANYフラグを設定して tpgetrply()の応答を待機しているときに、同じコンテキストの別のスレッドが tpgetrply(3c)を呼び出して特定のハンドルの取得を試みると、この呼出しは -1を返して tperrno(5)を TPEPROTOに設定します。
|
これは、1つのスレッドがすでに
tpgetrply()で特定のハンドルを待機しているときに、同じコンテキストの別のスレッドが
TPGETANYフラグを設定して
tpgetrply(3c)を呼び出した場合も同じです。これらの制約により、特定のハンドルを待機しているスレッドがある場合、その応答が別のスレッドに渡されることがなくなります。
|
•
|
ある時点で、 TPGETANYフラグを設定して tpgetrply(3c)の応答を待機できるのは、特定のコンテキスト内で1つのスレッドのみです。 TPGETANYフラグを設定して呼び出した tpgetrply()がまだ処理されていない場合に、同じコンテキストの別のスレッドが同じ呼出しを行うと、この2番目の呼出しは -1を返して tperrno(5)を TPEPROTOに設定します。
|
マルチスレッド・マルチコンテキスト環境の環境変数の使用
Oracle Tuxedoアプリケーションをマルチコンテキスト・マルチスレッド環境で実行する場合、環境変数に関して以下の事柄に注意してください。
|
•
|
プロセスは、初期状態ではその環境をオペレーティング・システム環境から継承します。環境変数がサポートされているプラットフォームでは、そのような変数はプロセス単位で動作するエンティティを構成します。そのため、コンテキスト単位の環境設定に依存するアプリケーションでは、オペレーティング・システム関数ではなく tuxgetenv(3c)関数を使用する必要があります。
|
|
注意:
|
オペレーティング・システム環境が認識されないオペレーティング・システムの場合、初期状態では空の環境になっています。
|
|
•
|
多くの環境変数は、Oracle Tuxedoシステムでプロセスごとに1回、またはコンテキストごとに1回だけ読み取られ、Oracle Tuxedoシステム内にキャッシュされます。プロセスに一度キャッシュされた変数を変更しても影響はありません。
|
|
•
|
tuxgetenv(3c)関数は、現在のコンテキストで要求された環境変数の現在の値を返します。初期設定では、すべてのコンテキストが同じ環境になります。ただし、特定のコンテキストに固有の環境ファイルを使用すると、コンテキストごとに異なる環境設定を持つことができます。
|
|
•
|
クライアントが複数のドメインに初期化する場合、 tpinit(3c)を呼び出す前に、毎回 TUXCONFIG、 WSNADDRまたは WSENVFILE環境変数の値を適切な値に変更する必要があります。そのようなアプリケーションがマルチスレッドの場合、以下の処理を確実に行うために、ミューテックスなどのアプリケーション定義の同時実行性制御が必要になります。
|
|
•
|
クライアントがシステムに初期化する場合、 WSENVFILEやマシン環境ファイルが読み取られ、そのコンテキストの環境だけが影響を受けます。環境ファイルでオーバーライドされないコンテキスト部分には、プロセス全体に対する以前の環境が適用されます。
|
マルチスレッドATMIクライアントでのコンテキスト単位の関数とデータ構造体
以下に示すATMI関数は、呼出し側のアプリケーション・コンテキストだけに影響します。
|
注意:
|
tpbroadcast(3c)の場合、ブロードキャスト・メッセージは特定のアプリケーションとの関連付けから送られたものとして識別されます。 tpnotify(3c)の場合、通知は特定のアプリケーションとの関連付けから送られたものとして識別されます。 tpinit(3c)の注記については、「マルチスレッド・クライアントでのプロセス単位の関数とデータ構造体」を参照してください。
|
tpsetunsol(3c)がコンテキストに関連付けされていないスレッドから呼び出されると、新しく生成されるすべての
tpinit(3c)コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ・ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに
tpsetunsol()を再度呼び出して、そのコンテキストの非請求メッセージ・ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ・ハンドラは、コンテキストに現在関連付けされていないスレッドで
tpsetunsol()を再度呼び出すと、変更できます。
|
•
|
CLIENTID、クライアント名、ユーザー名、トランザクションID、および TPSVCINFOデータ構造体の内容は、同じプロセス内のコンテキストによって異なる場合があります。
|
|
•
|
非同期呼出しハンドルと接続記述子は、その生成元コンテキスト内で有効です。任意通知のタイプは、コンテキストごとに固有です。シグナル・ベースの通知はマルチコンテキストでは使用できませんが、各コンテキストでは次のいずれかのオプションを使用できます。
|
マルチスレッドATMIクライアントでのプロセス単位の関数とデータ構造体
以下に示すOracle Tuxedo関数は、呼出し側のプロセス全体に影響します。
シングル・コンテキスト・モード、マルチコンテキスト・モード、または非初期化モードのどれを使用するかは、プロセス全体に影響します。また、バッファ・タイプ・スイッチ、ビュー・キャッシュ、および環境変数の値も、プロセス単位の関数です。
マルチスレッドATMIクライアントでのスレッド単位の関数とデータ構造体
以下に示す関数は、呼出し側のスレッドだけに影響します。
マルチスレッドATMIクライアントのサンプル・コード
次のサンプル・コードは、ATMI呼出しを使用するマルチスレッド・クライアントを示しています。スレッド関数は、オペレーティング・システムによって異なります。この例では、POSIX関数が使用されています。
|
注意:
|
コードを簡単にするために、エラー・チェックは省略してあります。
|
リスト10-4
マルチスレッド・クライアントのサンプル・コード
#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));
/*
* This code will perform a transfer, using separate threads for the
* withdrawal and deposit. It will also get the current
* price of BEA stock from a separate application, and calculate how
* many shares the transferred amount can buy.
*/
tpinitbuf->flags = TPMULTICONTEXTS;
/* Fill in the rest of tpinitbuf. */
tpinit(tpinitbuf);
tpgetctxt(&ctxt, 0);
tpbegin(timeout, 0);
pthread_create(&withdrawalthreadid, NULL, withdrawalthread, NULL);
tpcall("DEPOSIT", ...);
/* Wait for the withdrawal thread to complete. */
pthread_join(withdrawalthreadid, NULL);
tpcommit(0);
tpterm();
/* Wait for the stock thread to complete. */
pthread_join(stockthreadid, NULL);
/* Print the results. */
printf("$%9.2f has been transferred \
from your savings account to your checking account.\n", ...);
printf("At the current BEA stock price of $%8.3f, \
you could purchase %d shares.\n", ...);
exit(0);
}
void *
stockthread(void *arg)
{
/* The other threads have now called tpinit(), so resetting TUXCONFIG can
* no longer adversely affect them.
*/
tuxputenv("TUXCONFIG=/home/users/xyz/stockconf");
tpinitbuf->flags = TPMULTICONTEXTS;
/* Fill in the rest of tpinitbuf. */
tpinit(tpinitbuf);
tpcall("GETSTOCKPRICE", ...);
/* Save the stock price in a variable that can also be accessed in main(). */
tpterm();
return(NULL);
}
void *
withdrawalthread(void *arg)
{
/* Create a separate thread to get stock prices from a different
* application.
*/
pthread_create(&stockthreadid, NULL, stockthread, NULL);
tpsetctxt(ctxt, 0);
tpcall("WITHDRAWAL", ...);
return(NULL);
}
マルチスレッド/マルチコンテキストATMIアプリケーションのコードのコンパイル
buildserver(1)や
buildclient(1)など、コンパイルまたはビルドの実行可能ファイル用にOracle Tuxedoシステムで提供されるプログラムには、必要なコンパイラ・フラグが自動的に設定されます。これらのツールを使用すると、コンパイル時にフラグを設定する必要がありません。
ただし、最終的なコンパイルの前に
.cファイルを
.oファイルにコンパイルする場合は、プラットフォーム固有のコンパイラ・フラグを設定する必要があります。そのようなフラグは、単一のプロセスにリンクするすべてのコードに一貫して設定しなければなりません。
マルチスレッド・サーバーを生成する場合、
-tオプションを指定して
buildserver(1)コマンドを実行する必要があります。これはマルチスレッド・サーバーの場合に必須のオプションです。ビルド時にこのオプションが指定されておらず、その後、
MAXDISPATCHTHREADSの値が1を超える構成ファイルを使用して新しいサーバーを起動すると、警告メッセージがユーザー・ログに記録され、サーバーはシングル・スレッドの動作に戻ります。
マルチスレッド環境で
.cファイルを
.oファイルにコンパイルする場合に必要なオペレーティング・システム固有のコンパイラ・パラメータを識別するには、
-vオプションを指定して
buildclient(1)または
buildserver(1)をテスト・ファイルで実行します。
マルチスレッド/マルチコンテキストATMIアプリケーションのテスト
マルチスレッド/マルチコンテキストATMIアプリケーションのテスト時の推奨事項
マルチスレッドやマルチコンテキストのコードをテストする場合、以下を行うことをお薦めします。
|
•
|
マルチスレッド・デバッガの使用(オペレーティング・システムのベンダーから提供されている場合)
|
マルチスレッド/マルチコンテキストATMIアプリケーションのトラブルシューティング
エラーの原因を調べる場合、まず
TPMULTICONTEXTSフラグが設定されているかどうか、またその設定内容を確認します。このフラグが設定されていないこと、または正しく設定されていないことが原因でよくエラーが起こります。
tpinit( )のTPMULTICONTEXTSフラグの間違った使用
TPMULTICONTEXTSフラグを使用できない場合にこのフラグがプロセスに設定されているとき、または
TPMULTICONTEXTSを設定する必要がある場合に設定されていないとき、
tpinit(3c)は
-1を返し、
tperrnoを
TPEPROTOに設定します。
TPMULTICONTEXTSが設定されていない場合のtpinit()の呼出し
TPMULTICONTEXTSが設定されていない場合に
tpinit(3c)が呼び出されると、この関数はシングル・コンテキスト・アプリケーションで呼び出されたときと同じように動作します。
tpinit()がすでに1回呼び出されている場合、それ以降の
tpinit()呼出しで
TPMULTICONTEXTSフラグが設定されていなくても、この関数は正常に終了します。これは、アプリケーション内の
TUXCONFIGまたは
WSNADDR環境変数の値が変更されている場合にも当てはまります。
TPMULTICONTEXTSフラグを設定せずに
tpinit()を呼び出すことは、マルチコンテキスト・モードではできません。
クライアントがアプリケーションに参加していない場合に、
tpinit()を呼び出す別の関数の呼出しの結果として、暗黙的に
tpinit(3c)が呼び出されると、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()の引数として指定されます。この問題の詳細は、お使いのオペレーティング・システムのドキュメントを参照してください。
マルチスレッド/マルチコンテキストATMIアプリケーションのエラー処理
エラーはユーザー・ログに記録されます。シングル・コンテキスト・モードでもマルチコンテキスト・モードでも、各エラーに対して次の情報が記録されます。
process_ID.thread_ID.context_ID