目次 前 次 PDF


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

マルチスレッドおよびマルチコンテキストATMIアプリケーションのプログラミング
このトピックには次の項が含まれます:
マルチスレッド/マルチコンテキストATMIアプリケーションのプログラミングに対するサポート
Oracle Tuxedoシステムでは、次のアプリケーションがサポートされています。
カーネル・レベルのスレッド・パッケージ(ユーザー・レベルのスレッド・パッケージはサポートされていません)。
C言語で記述されたマルチスレッド・アプリケーション(COBOLでのマルチスレッド・アプリケーションはサポートされていません)。
C言語またはCOBOL言語で記述されたマルチコンテキスト・アプリケーション。
お使いのオペレーティング・システムでPOSIXスレッド関数と共にほかのスレッド関数がサポートされている場合は、POSIXスレッド関数を使用することをお薦めします。この関数を使用すると、後でコードをほかのプラットフォームに簡単に移植できます。
お使いのプラットフォームでカーネル・レベルのスレッド・パッケージ、C言語の関数、またはPOSIX関数がサポートされているかどうかを確認するには、『Oracle Tuxedoシステムのインストール』「Oracle Tuxedo 11gリリース1 (11.1.1.3.0)プラットフォーム・データ・シート」の使用しているオペレーティング・システムのデータ・シートに関する項を参照してください。
マルチスレッドおよびマルチコンテキスト・アプリケーションに関するプラットフォーム固有の検討事項
多くのプラットフォームには、マルチスレッドおよびマルチコンテキスト・アプリケーション固有の要件があります。プラットフォーム固有の要件については、『Oracle Tuxedoシステムのインストール』「Oracle Tuxedo 11gリリース1 (11.1.1.3.0)プラットフォーム・データ・シート」に説明があります。お使いのプラットフォームの要件については、該当するデータ・シートを参照してください。
関連項目
マルチスレッド/マルチコンテキストATMIアプリケーションの計画と設計
このトピックには次の項が含まれます:
マルチスレッドおよびマルチコンテキストとは
Oracle Tuxedoシステムでは、単一のプロセスで複数のタスクを同時に実行できます。このようなプロセスを実装するプログラミング手法はマルチスレッドおよびマルチコンテキストと呼ばれます。この項では、これらの手法に関する基本事項について説明します。
マルチスレッドとは
マルチスレッドとは、1つのプロセスに複数の実行単位が含まれている処理方法です。マルチスレッド・アプリケーションでは、同じプロセスから同時に複数の呼出しを行うことができます。たとえば、個々のプロセスが1つの未終了のtpcall()に制限されることはありません。
サーバーのマルチスレッドでは、アプリケーション生成のスレッドがシングル・コンテキスト・サーバーで使用される場合を除き、マルチコンテキストが必要です。マルチスレッドのシングル・コンテキスト・アプリケーションを作成する唯一の方法は、アプリケーション生成のスレッドを使用することです。
Oracle Tuxedoシステムでは、C言語で記述されたマルチスレッド・アプリケーションがサポートされています。COBOL言語のマルチスレッド・アプリケーションはサポートされていません。
図10-1は、マルチスレッド・クライアントが3つのサーバーに対して同時に呼出しを行う方法を示しています。
図10-1 マルチスレッド・プロセスの例
マルチスレッド・アプリケーションでは、同じサーバーで複数のサービス・ディスパッチ・スレッドを使用できるので、アプリケーションに対して起動するサーバー数が少なくて済みます。
図10-2は、異なるクライアントに対して、サーバー・プロセスが同時に複数のスレッドをディスパッチする方法を示しています。
図10-2 1つのサーバー・プロセスによる複数のサービス・スレッドのディスパッチ
マルチコンテキストとは
コンテキストはドメインへの関連付けです。マルチコンテキストを使用すると、1つのプロセスで次のいずれかが可能になります。
ドメイン内での複数接続
複数ドメインへの接続
マルチコンテキストは、クライアントとサーバーの両方で使用できます。サーバーでマルチコンテキストを使用すると、マルチスレッドも使用することになります。
コンテキストの特徴の詳細は、次のいずれかの項で「コンテキストの属性」を参照してください。
Oracle Tuxedoシステムでは、C言語またはCOBOL言語のいずれかで記述されたマルチコンテキスト・アプリケーションがサポートされています。ただし、サポートされるマルチスレッド・アプリケーションは、C言語で記述されたものだけです。
図10-3は、ドメイン内でのマルチコンテキスト・クライアント・プロセスの動作を示しています。各矢印はサーバーへの未終了の呼出しを表します。
図10-3 2つのドメイン内でのマルチコンテキスト・プロセス
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションの監査
各コンテキストは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()を呼び出して、1つ以上のOracle Tuxedoアプリケーションに参加します。
その他のクライアント・スレッドはtpsetctxt(3c)を呼び出して、最初のスレッド・セットによって生成されるコンテキストを共有します。
一部のクライアント・スレッドは複数のコンテキストに参加します。
一部のクライアント・スレッドは既存のコンテキストに切り替えます。
注意:
Oracle Tuxedoシステムから独立して動作するスレッドが存在する場合もあります。ここでは、そのようなスレッドについては説明していません。
クライアント・スレッドの複数コンテキストへの参加
Oracle Tuxedoマルチコンテキスト・アプリケーションのクライアントは、次の規則に従うかぎり、複数のアプリケーションに関連付けることができます。
すべての関連付けは、Oracle Tuxedoシステムの同じインストールに対して行う必要があります。
すべてのアプリケーションとの関連付けは、同じタイプのクライアントから行う必要があります。つまり、次のいずれかの条件を満たしている必要があります。
すべてのアプリケーションとの関連付けは、ネイティブ・クライアントから行う必要があります。
すべてのアプリケーションとの関連付けは、ワークステーション・クライアントから行う必要があります。
クライアントが複数のコンテキストに参加するには、TPINFOデータ型のflags要素にTPMULTICONTEXTSフラグを設定して、tpinit()関数を呼び出します。
TPMULTICONTEXTSフラグを設定してtpinit()関数が呼び出されると、アプリケーションとの新しい関連付けが生成され、スレッドに対するカレントの関連付けが指定されます。新しい関連付けが生成されるOracle Tuxedoドメインは、TUXCONFIGまたはWSENVFILE/WSNADDR環境変数の値で決定されます。
クライアント・スレッドの既存のコンテキストへの切り替わり
多くのATMI関数はコンテキスト単位で動作します。このようなATMI関数のリストについては、10-48ページの「マルチスレッドATMIクライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。コンテキスト単位で動作するには、ターゲット・コンテキストが現在のコンテキストであることが必要です。クライアントは複数のコンテキストに参加できますが、状況とスレッドにかかわらず現在のコンテキストになることができるコンテキストは1つだけです。
アプリケーション内でタスクの優先度が移り、ほかのOracle Tuxedoドメインと通信する必要が発生した場合、あるコンテキストから別のコンテキストにスレッドを再割り当てした方がよい場合があります。
そのような場合、あるクライアント・スレッドがtpgetctxt(3c)を呼び出し、返された現在のコンテキストを値として持つハンドルを別のクライアント・スレッドに渡します。2番目のスレッドはtpsetctxt(3c)を呼び出し、最初のスレッドでtpgetctxt(3c)から受け取ったハンドルを指定して、現在のコンテキストとの関連付けを確立します。
目的のコンテキストとの関連付けが確立されると、2番目のスレッドはコンテキスト単位で動作するATMI関数を使用してタスクを実行できるようになります。詳細は、10-48ページの「マルチスレッドATMIクライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。
作業フェーズ
このフェーズでは、各スレッドによって処理が行われます。次は、行われる処理の例です。
サービスをリクエストします。
サービス・リクエストに対する応答を受け取ります。
会話を開始して会話に参加します。
トランザクションの開始、コミット、またはロールバックを行います。
サービス・リクエスト
スレッドは、同期リクエストの場合はtpcall()、非同期リクエストの場合はtpacall()を呼び出して、サーバーにリクエストを送ります。tpcall()でリクエストを送った場合、以降操作を行わなくても応答を受け取ることができます。
サービス・リクエストに対する応答
tpacall()でサービスの非同期リクエストを送った場合、同じコンテキスト内のスレッドはtpgetrply()を呼び出して応答を受け取ります。このスレッドは、リクエストを送ったスレッドと同じスレッドではない場合もあります。
トランザクション
あるスレッドがトランザクションを開始すると、そのスレッドのコンテキストを共有するすべてのスレッドでそのトランザクションが共有されます。
コンテキスト内の多くのスレッドでトランザクションに関する処理が行われますが、トランザクションをコミットまたは中断できるのは1つのスレッドだけです。トランザクションをコミットまたは中断するスレッドは、トランザクションを開始したスレッドである必要はなく、トランザクションを処理しているどのスレッドでもかまいません。スレッド・アプリケーションでは、通常のトランザクション規則に従うために、適切に同期を行う必要があります。たとえば、未終了のRPC呼び出しや会話がある場合に、トランザクションをコミットすることはできません。また、トランザクションがコミットまたは中断された後で、そのトランザクションに対する呼出しを行うことはできません。プロセスは、アプリケーションの各関連付けに対して、1つのトランザクションの一部にだけなることができます。
アプリケーションの1つのスレッドがtpcommit()を呼び出し、それと同時に別のスレッドがRPC呼び出しまたは会話型呼出しを行うと、これらの呼出しは特定の順序で呼び出されたものとして処理されます。アプリケーション・コンテキストは、シングル・スレッド・プログラムとシングル・コンテキスト・プログラムに対する制約と同じ制約に従って、tpsuspend()を呼び出してトランザクションを一時的に中断し、別のトランザクションを開始します。
非請求メッセージ
マルチスレッド・アプリケーションまたはマルチコンテキスト・アプリケーションの各コンテキストでは、非請求メッセージを次の3種類のいずれかの方法で処理できます。
 
処理方法
設定
非請求メッセージの無視
TPU_IGN
ディップ・イン通知
TPU_DIP
専用のスレッド通知
(C言語のアプリケーションのみで利用可能です)
TPU_THREAD
以下の事柄に注意してください。
シグナル・ベースの通知は、マルチスレッド・プロセスまたはマルチコンテキスト・プロセスでは使用できません。
アプリケーションを実行しているプラットフォームで、マルチコンテキストがサポートされていてもマルチスレッドがサポートされていない場合、TPU_THREADを使用した非請求通知の処理を行うことはできません。そのため、イベントの即時通知を受け取ることはできません。
イベントの即時通知を受け取る必要がある場合は、そのプラットフォームでマルチコンテキストを使用するかどうかを慎重に検討します。
専用のスレッド通知は、次のものに対してだけ使用できます。
C言語で記述されたアプリケーション
Oracle Tuxedoシステムでサポートされているマルチスレッド・プラットフォーム
専用のスレッド通知の場合、非請求メッセージの受信と、非請求メッセージ・ハンドラのディスパッチに別々のスレッドが使用されます。あるコンテキストで一度に実行できる非請求メッセージ・ハンドラは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()が呼び出される前に、すべてのスレッドが同期していなければなりません。
関連項目
ATMIサーバーでのサーバー・ディスパッチ・スレッドのマルチスレッドとマルチコンテキストの動作
マルチスレッドおよびマルチコンテキスト・アプリケーションがアクティブの場合、ATMIサーバーで行われる処理は次の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つのサーバーに対する複数のクライアント・リクエストが、複数のコンテキストで同時に処理されます。リクエストごとに別のスレッドが割り当てられます。
必要に応じて、MAXDISPATCHTHREADSで指定された値まで新しいスレッドが生成されます。
サーバー・スレッドの統計がシステムで保持されます。
サーバー・ディスパッチ・スレッドの使用方法
クライアントのサービス・リクエストへのレスポンスとして、サーバー・ディスパッチャは各種のクライアント・リクエストに同時に割り当てることができる1つのサーバーに、設定可能な最大数まで複数のスレッドを生成します。サーバーがtpinit()を呼び出すことはできません。
各ディスパッチ・スレッドは、別々のコンテキストと関連付けられています。この機能は会話型サーバーとRPCサーバーの両方で有用です。特に、会話型サーバーではこの機能を利用できないと、ほかの会話接続がサービスを待っている間、クライアント側の会話をアイドル状態で待つことになります。
この機能は、UBBCONFIG(5)ファイルのSERVERSセクションおよびTM_MIB(5)の次のパラメータで制御されます。
 
UBBCONFIGパラメータ
MIBパラメータ
デフォルト
MINDISPATCHTHREADS
TA_MINDISPATCHTHREADS
0
MAXDISPATCHTHREADS
TA_MAXDISPATCHTHREADS
1
THREADSTACKSIZE
TA_THREADSTACKSIZE
0 (オペレーティング・システムのデフォルト値)
各ディスパッチ・スレッドは、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を超えるサーバー・スレッドを起動することはありません。
BBLによるシステム・プロセスの正常性チェック
BBLは定期的にサーバーを検証します。特定のサービス・リクエストの実行に時間がかかりすぎている場合、BBLはそのサーバーを強制終了します。(そして、指定されている場合は、そのサーバーを再起動します。)BBLがマルチコンテキスト・サーバーを強制終了した場合、プロセスを強制終了した結果として、実行中のそのほかのサービス呼び出しも終了します。
また、BBLはタイムアウト値を超えてメッセージの受信を待機しているプロセスまたはスレッドにメッセージを送信します。すると、ブロッキング・メッセージ受信への呼出しが、タイムアウトを示すエラーを返します。
システムで保持されるサーバー・スレッドの統計
Oracle Tuxedoシステムでは、各サーバーに対して次の統計情報が保持されます。
使用できるサーバー・ディスパッチ・スレッドの最大数
現在使用中のサーバー・ディスパッチ・スレッドの数(TA_CURDISPATCHTHREADS)
サーバー起動後の同時実行サーバー・ディスパッチ・スレッドの最大数(TA_HWDISPATCHTHREADS)
これまでに起動したサーバー・ディスパッチ・スレッドの数(TA_NUMDISPATCHTHREADS)
ユーザー・ログで保持されるスレッド固有の情報
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)が呼び出されて、リソース・マネージャのクローズなど、必要な終了処理が行われます。
関連項目
ATMIサーバーのアプリケーション生成スレッドのマルチスレッドとマルチコンテキストの動作
オペレーティング・システム関数を使用して、Tuxedoアプリケーション・サーバー内に新しいスレッドを追加できます。最初、アプリケーション生成サーバー・スレッドは、どのTuxedoコンテキストにも関連していません。アプリケーション生成のスレッドは、次のように動作します。
Tuxedoシステムから独立して動作します。
tpappthrinit(3c)によって生成されたコンテキストで動作します。(この機能は、Tuxedo 11gリリース1 (11.1.1.3.0)で利用できます)。
既存のサーバー・ディスパッチ・スレッドと同じコンテキストで動作し、サーバー・ディスパッチ・コンテキストのかわりに機能します。
この状況では、アプリケーション生成のサーバー・スレッドはtpsetctxt(3c)を呼び出し、サーバー・ディスパッチ・スレッド内の以前のtpgetctxt(3c)呼出しによって返される値を渡して、サーバー・ディスパッチ・コンテキストとの関連付けを確立します。
サーバー・ディスパッチ・コンテキストに関連付けられたアプリケーション生成のサーバー・スレッドは、処理が終了したら、元のディスパッチ・スレッドがtpreturn()を呼び出す前に、tpsetctxt(3c)を呼び出してTPNULLCONTEXTに設定する必要があります。
アプリケーション生成のスレッドは、tpreturn()およびtpforward()を呼び出すことはできません。
アプリケーション生成のサーバー・スレッドは別のTuxedoコンテキストを生成し、tpappthrinit(3c)を使用してこのコンテキストに自身を関連付けることができます。アプリケーション生成のサーバー・スレッドがアクティブな場合、tpappthrinit(3c)によって生成されたTuxedoコンテキストのライフサイクルは、次の3つのフェーズから構成されます。
起動フェーズ
アプリケーション生成のサーバー・スレッドはTuxedoコンテキストを生成し、tpappthrinit(3c)を呼び出すことによってこのコンテキストに自身を関連付けます。tpappthrinit(3c)によって生成されたコンテキストは、アプリケーション・サーバーが存在するドメインに接続します。
必要に応じて、tpappthrinit(3c)を正常に呼び出した後、ATMIサーバー内のアプリケーション生成のスレッドがtpgetctxt(3c)を呼び出し、返されるハンドル(現在のコンテキストの値)を同じプロセス内の別のアプリケーション・スレッドに渡します。
作業フェーズ
各アプリケーション生成のサーバー・スレッドによって、次の処理が行われます。
サービスをリクエストします。
サービス・リクエストに対する応答を受け取ります。
会話を開始して会話に参加します。
トランザクションの開始、コミット、またはロールバックを行います。
アプリケーション生成のサーバー・スレッドで実行されるこれらの処理は、クライアント・プログラムの場合と同様の特徴を持っています。詳細は、「クライアントでのマルチスレッドとマルチコンテキストの動作」を参照してください。
注意:
アプリケーション生成のサーバー・スレッドは、tpreturn()およびtpforward()を呼び出すことはできません。
アプリケーション生成のサーバー・スレッドは、非請求メッセージを送信することはできますが、受信することはできません。
ユーザー・ログで保持されるスレッド固有の情報
userlog(3c)を使用すると、ATMIサーバーの各アプリケーション生成スレッドに対する識別情報(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)を呼び出す前に、すべてのアプリケーション・スレッドが同期しているかを確認してください。
関連項目
クライアントでのマルチスレッドとマルチコンテキストの動作
マルチスレッドおよびマルチコンテキストATMIアプリケーションの設計上の検討事項
ATMIサーバーのアプリケーション生成スレッドでマルチコンテキストを使用するためのコーディング
ATMIサーバーでサーバー・ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング
マルチスレッドATMIクライアントのコーディング
マルチスレッドおよびマルチコンテキスト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で混在モードがサポートされていることを確認します。
設計の要件
マルチスレッド・アプリケーションやマルチコンテキスト・アプリケーションの設計では、次の内容を検討します。
マルチスレッドやマルチコンテキストに適するアプリケーションのタスク
次の表は、アプリケーションをマルチスレッドまたはマルチコンテキストにすべきかどうかを判断するための参考となる検討事項を示しています。この表だけでは十分ではないので、個々の要件に基づいてほかの事項も検討してください。
そのほかの検討事項については、マルチスレッド・アプリケーションやマルチコンテキスト・アプリケーションのプログラミングに関する書籍を参照してください。
 
検討事項
検討事項に該当する場合に使用する機能
ドメイン機能を使用せずに、クライアントが複数のアプリケーションに接続する必要があるか
マルチコンテキスト。
アプリケーション内でクライアントが多重化の機能を果たすか。たとえば、アプリケーション内の1つのマシンがそのほかの100台のマシンの「代理」に指定されているか
マルチコンテキスト。
クライアントでマルチコンテキストが使用されるか
マルチスレッド。各コンテキストにスレッドを1つずつ割り当てると、コードを簡略化できます。
クライアントが2つ以上のタスクを長時間個別に実行することで、並列処理によるパフォーマンスがスレッド同期のコストと複雑さを上回るか
マルチスレッド。
1つのサーバーで複数のリクエストを同時に処理するか
マルチスレッド。MAXDISPATCHTHREADSに1より大きな値を割り当てます。このように設定すると、1つのサーバーで複数のクライアントをそのクライアントのスレッドで処理できるようになります。
アプリケーション生成のサーバー・スレッドでATMI呼出しを実行するか
マルチスレッド。
アプリケーション生成のサーバー・スレッドは別のTuxedoコンテキストを生成し、tpappthrinit(3c)を呼び出すことによってこのコンテキストに自身を関連付けます(この機能はTuxedo 11gリリース1(11.1.1.3.0)で利用できます)。
クライアントまたはサーバーに複数のスレッドがある場合、各スレッドでわずかな処理を行った後でもスレッドを同期する必要があるか
マルチスレッドを使用しません。
必要なアプリケーションと接続の数
アクセスするアプリケーションの数と、確立する接続の数を決定します。
複数のアプリケーションに接続する場合は、次のいずれかを使用します。
シングル・スレッドおよびマルチコンテキスト・アプリケーション
マルチスレッドおよびマルチコンテキスト・アプリケーション
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システムのインストール』「Oracle Tuxedo 11gリリース1 (11.1.1.3.0)プラットフォーム・データ・シート」を参照してください。
マルチスレッド・サーバーを使用している場合は、これらのサーバーで使用されるリソース・マネージャでスレッドがサポートされていることが必要です。
マルチスレッド・アプリケーションのプログラミングでの一般的な検討事項
マルチスレッド・プログラムは、十分に経験を持つプログラマがコーディングします。特に、次のようなマルチスレッド固有の設計に関する基本的な知識があることが必要です。
複数スレッド間の同時実行性制御の必要性
ほどんどのインスタンスで静的変数の使用を避ける必要性
マルチスレッド・プログラムでシグナルを使用することにより発生する可能性のある問題
これらは検討事項の一部にすぎず、ここに記せないほど多くの検討事項があります。マルチスレッド・プログラムをコーディングするプログラマは、それらの検討事項を熟知していることが前提となります。これらの検討事項については、マルチスレッド・アプリケーションのプログラミングに関する書籍を参照してください。
同時実行性に関する検討事項
マルチスレッドを使用すると、1つのアプリケーションの異なるスレッドが同じ会話で並列処理を行うことができるようになります。この方法はお薦めしませんが、Oracle Tuxedoシステムで禁止されているわけではありません。異なるスレッドによって同じ会話で並列処理が行われると、システムは同時呼出しが任意の順序で行われたように動作します。
複数のスレッドを使ってプログラミングする場合、ミューテックスなどの同時実行性制御関数を使用して、スレッド間の並列処理を管理する必要があります。以下は、同時実行性制御が必要になる3つの例です。
マルチスレッドのスレッドが同じコンテキストで動作する場合、プログラマは関数が必要な順序で実行されるようにします。たとえば、すべてのRPC呼出しと会話が完了した後でのみ、tpcommit()を呼び出すようにします。これらすべてのRPC呼び出しまたは会話型呼出しが行われるスレッドとは別のスレッドからtpcommit()が呼び出される場合、アプリケーションで何らかの同時実行性制御が必要になります。
同じように、tpacall()tpgetrply()の呼出しを別々のスレッドで行うことはできますが、アプリケーションが次のいずれかの条件を満たしている必要があります。
tpacall()が呼び出された後でtpgetrply()が呼び出されます。
tpacall()を呼び出す前にtpgetrply()が呼び出される場合、結果が管理されます。
複数のスレッドが同じ会話で処理を行うことは可能です。ただし、異なるスレッドがtpsend()をほとんど同時に呼び出した場合、システムはそれらのtpsend()呼出しが任意の順序で行われたように動作します。アプリケーション・プログラマは、それを認識しておかなければなりません。
ほとんどのアプリケーションで最良の戦略は、1つの会話のすべての処理を1つのスレッドにまとめてコーディングすることです。次善の戦略は、同時実行性制御を使用して、これらの処理を連続して行うことです。
関連項目
ATMIクライアントでマルチコンテキストを使用するためのコーディング
この項には次のトピックが含まれます:
アプリケーションでトランザクションを使用する場合、トランザクションのマルチコンテキストの結果についても注目します。詳細は、10-33ページの「マルチスレッド/マルチコンテキストATMIアプリケーションにおけるトランザクションのコーディング規則」を参照してください。
注意:
この項で示す手順とサンプル・コードは、Oracle Tuxedoシステムで提供されるC言語のライブラリ関数を参照します。それらに相当するCOBOLライブラリ関数も利用できます。詳細については、『Oracle Tuxedo COBOL関数リファレンス』を参照してください。
コンテキストの属性
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
元のディスパッチ・スレッドが終了する前に、サーバー・ディスパッチ・コンテキストに現在関連付けられているアプリケーション生成のサーバー・スレッドがコンテキストを変更せずに終了すると、tpreturn()またはtpforward()が失敗します。スレッドを終了しても、自動的にtpsetctxt(3c)の呼出しがトリガーされてコンテキストがTPNULLCONTEXTに変更されることはありません。
プロセス内のすべてのコンテキストに、同じバッファ・タイプ・スイッチを使用します。
ほかのタイプのデータ構造体と同じように、マルチスレッド・アプリケーションではOracle Tuxedoバッファを適切に使用する必要があります。つまり、次のいずれかが該当する場合、バッファを2つの呼出しで同時に使用することはできません。
両方の呼出しでバッファを使用する場合
両方の呼出しでバッファを解放する場合
1つの呼出しでバッファを使用し、もう1つの呼出しでバッファを解放する場合
tpinit()を複数回呼び出して、複数アプリケーションに参加するか、または単一アプリケーションに複数の接続を行う場合、tpinit()を呼び出すたびに、確立されているセキュリティ・メカニズムを調整する必要があります。
初期化時のマルチコンテキストの設定
クライアントがアプリケーションに参加する準備ができたら、リスト10-1に示すように、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フラグを含む必要のない状態にプロセスが復元されます。
マルチコンテキストATMIクライアントのセキュリティの実装
同じプロセス内の各アプリケーションとの関連付けには、別個にセキュリティ検証を行う必要があります。検証の内容は、アプリケーションで使用されているセキュリティ・メカニズムのタイプによって異なります。たとえば、Oracle Tuxedoアプリケーションでは、システム・レベルのパスワードまたはアプリケーション・パスワードを使用します。
マルチコンテキスト・アプリケーションのプログラマは、アプリケーションで使用するセキュリティのタイプを決定し、そのセキュリティをプロセス内の各アプリケーションとの関連付けに実装します。
ATMIクライアント終了前のスレッドの同期
クライアントをアプリケーションから切断する準備ができたら、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()を呼び出して、2番目のアプリケーションに参加します。
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 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 Oracle 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()がコンテキストに関連付けされていないスレッドから呼び出されると、新しく生成されるすべてのtpinit()コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ・ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときにtpsetunsol()を再度呼び出して、そのコンテキストの非請求メッセージ・ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ・ハンドラは、コンテキストに現在関連付けされていないスレッドでtpsetunsol()を再度呼び出すと、変更できます。
ハンドラの設定は、シングル・スレッド・アプリケーションまたはシングル・コンテキスト・アプリケーションのハンドラを設定する場合と同じように行います。詳細は、「tpsetunsol()」を参照してください。
現在処理を行っているコンテキストを識別するには、非請求メッセージ・ハンドラ内でtpgetctxt(3c)を使用します。
マルチスレッド/マルチコンテキストATMIアプリケーションにおけるトランザクションのコーディング規則
トランザクションを使用する場合、コーディングで以下の事柄に注意してください。
1つのコンテキストで所有できるトランザクションは1つだけです。
各コンテキストで異なるトランザクションを使用できます。
ある時点で任意のコンテキストに関連付けされているすべてのスレッドは、そのコンテキストの同じトランザクション状態を共有します。
スレッドを同期して、すべての会話とRPC呼出しが完了してからtpcommit()が呼び出されるようにします。
tpcommit()の呼出しは、特定のトランザクションの1つのスレッドからのみ行うことができます。
関連項目
ATMIサーバーでサーバー・ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング
このトピックには次の項が含まれます:
注意:
この項で示す手順とサンプル・コードは、Oracle Tuxedoシステムで提供されるC言語のライブラリ関数を参照します。(詳細は、『Oracle Tuxedo C関数リファレンス』を参照してください。)COBOLアプリケーションではマルチコンテキスト・サーバーの生成に必要なマルチスレッドがサポートされていないので、C言語の関数に相当するCOBOLルーチンは利用できません。
コンテキストの属性
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
元のディスパッチ・スレッドが終了する前に、サーバー・ディスパッチ・コンテキストに現在関連付けられているアプリケーション生成のサーバー・スレッドがコンテキストを変更せずに終了すると、tpreturn()またはtpforward()が失敗します。スレッドを終了しても、自動的にtpsetctxt(3c)の呼出しがトリガーされてコンテキストがTPNULLCONTEXTに変更されることはありません。
プロセス内のすべてのコンテキストに、同じバッファ・タイプ・スイッチを使用します。
ほかのタイプのデータ構造体と同じように、マルチスレッド・アプリケーションではOracle Tuxedoバッファを適切に使用する必要があります。つまり、次のいずれかが該当する場合、バッファを2つの呼出しで同時に使用することはできません。
両方の呼出しでバッファを使用する場合
両方の呼出しでバッファを解放する場合
1つの呼出しでバッファを使用し、もう1つの呼出しでバッファを解放する場合
マルチコンテキストATMIサーバーでのサーバー・ディスパッチ・スレッドのコーディング規則
マルチコンテキスト・サーバー使用する場合、コーディングで以下の規則に注意してください。
サーバー上のOracle Tuxedoディスパッチャは、同じサービスまたは異なるサービスを複数回ディスパッチでき、ディスパッチされるサービスごとに異なるディスパッチ・コンテキストを生成します。
サーバーは、tpinit()を呼び出すことはできません。サーバー・プロセスでtpinit()が呼び出されると、tpinit()-1を返してtperrno(5)TPEPROTOに設定します。
サーバー・ディスパッチ・スレッドだけがtpreturn()またはtpforward()を呼び出すことができます。
アプリケーション生成のスレッドが任意のアプリケーションのコンテキストに関連付けされている場合、サーバーはtpreturn()またはtpforward()を実行できません。そのため、サーバー・ディスパッチ・スレッドがtpreturn()を呼び出す前に、そのコンテキストに対応するアプリケーション生成の各スレッドがコンテキストをTPNULLCONTEXTまたは別の有効なコンテキストに設定してtpsetctxt(3c)を呼び出す必要があります。
この規則に違反すると、tpreturn()またはtpforward()はユーザー・ログにメッセージを書き込み、呼出し側にTPESVCERRを示して、メイン・サーバーのディスパッチ・ループに制御を戻します。無効tpreturn()が実行されたコンテキスト内のスレッドは、無効コンテキスト状態になります。
tpreturn()またはtpforward()が呼び出された時点で未終了のATMI呼び出し、RPC呼び出し、または会話があると、tpreturn()またはtpforward()はユーザー・ログにメッセージを書き込み、呼出し側にTPESVCERRを示して、メイン・サーバーのディスパッチ・ループに制御を戻します。
サーバー・ディスパッチ・スレッドでtpsetctxt(3c)を呼び出すことはできません。
シングル・コンテキストのサーバーとは異なり、マルチコンテキスト・サーバー・スレッドでは、同じサーバー・プロセスだけで提供されるサービスを呼び出すことができます。
ATMIサーバーおよびATMIサーバー・スレッドの初期化と終了
サーバーとサーバー・スレッドの初期化と終了には、Oracle Tuxedoシステムで提供されるデフォルトの関数を使用できます。
 
表10-1 初期化と終了を行うデフォルトの関数
目的
使用するデフォルトの関数
サーバーを初期化します。
サーバー・スレッドの初期化
サーバーを終了します。
サーバー・スレッドの終了
関連項目
10-14ページの「ATMIサーバーでのサーバー・ディスパッチ・スレッドのマルチスレッドとマルチコンテキストの動作」
ATMIサーバーのアプリケーション生成スレッドでマルチコンテキストを使用するためのコーディング
このトピックには次の項が含まれます:
スレッドの生成
オペレーティング・システムのスレッド関数を使用して、Tuxedoアプリケーション・サーバーに新しいスレッドを生成できます。これらの新しいアプリケーションは、Tuxedoシステムから独立して動作できます。また、いずれかのサーバー・ディスパッチ・スレッドと同じコンテキストで動作することもできます。アプリケーション生成のサーバー・スレッドは、tpappthrinit(3c)によって生成された別のコンテキストで動作することもできます。
コンテキストへのアプリケーション・スレッドの関連付け
最初、アプリケーション生成サーバー・スレッドは、どのTuxedoコンテキストにも関連していません。ただし、初期化される前に呼び出された場合、ほとんどのATMI関数は暗黙的にtpinit()を実行します。サーバーでtpinit()を呼び出すことは禁止されているので、そのような呼出しを行うと問題が発生します。(サーバー・プロセスでtpinit()が呼び出されると、tpinit()-1を返してtperrno(5)TPEPROTOを設定します。)
そのため、アプリケーション生成のサーバー・スレッドは、有効なコンテキストと関連付けを行ってからATMI関数を呼び出す必要があります。アプリケーション生成のサーバー・スレッドは、次のように動作します。
自身を既存のサーバー・ディスパッチ・コンテキストに関連付けます。
自身をtpappthrinit(3c)によって生成された別のコンテキストに関連付ける(この機能は、Tuxedo 11gリリース1(11.1.1.3.0)で利用できます)。
既存のサーバー・ディスパッチ・コンテキストへのアプリケーション・スレッドの関連付け
アプリケーション生成のサーバー・スレッドを既存のサーバー・ディスパッチ・コンテキストに関連付けるには、以下の手順をコーディングします。
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);
}
 
アプリケーション生成のコンテキストへのアプリケーション・スレッドの関連付け
ATMIサーバー内のアプリケーション生成のATMIサーバー・スレッドは別のTuxedoコンテキストを生成し、tpappthrinit(3c)を呼び出してこのコンテキストに自身を関連付けることができます。
コンテキストの属性
tpappthrinit(3c)で作成されるコンテキストは、サーバー・ディスパッチ・コンテキストには依存していません。アプリケーション・サーバーがあるドメインに関連します。
tpappthrinit(3c)によって生成されたコンテキストは、アプリケーション生成のサーバー・スレッドがそのコンテキストでの処理を終了した後に、tpappthrterm(3c)を呼び出して終了する必要があります。
アプリケーションで使用されるセキュリティ・メカニズムのタイプによっては、tpappthrinit(3c)を呼び出す際に、ユーザー認証情報をコンテキストと関連付けることができます。アプリケーション生成コンテキストの各アプリケーションとの関連付けには、別個にセキュリティ検証を行う必要があります。
アプリケーション生成のコンテキストでのATMIサーバーのアプリケーション生成スレッドのコーディング規則
tpappthrinit()/tpappthrterm()を呼び出すことができるのは、Tuxedoサーバー・プロセスのみです。
buildserverコマンドを実行する場合、"-t"オプションを指定してサーバーをビルドする必要があります。
クライアント・プログラムでtpappthrinit()/tpappthrterm()を呼び出すことはできません。
サーバー・ディスパッチ・スレッドでtpappthrinit()/tpappthrterm()を呼び出すことはできません。
サーバー・ディスパッチ・コンテキストに現在関連付けられているアプリケーション生成スレッドでtpappthrterm()を呼び出すことはできません。
アプリケーション生成のコンテキストでほかのアプリケーション・スレッドがまだ処理を行っている場合は、そのコンテキストでtpappthrterm()を呼び出さないようにする必要があります。
ハンドルと呼出し記述子は、同じプロセスの同じコンテキスト内で移植できます。ただし、ほかのコンテキストやプロセスには移植できません。ハンドルと呼出し記述子は、それらが元々割り当てられていたアプリケーション・コンテキストだけで使用できます。
会話が開始されると、同じプロセスの同じコンテキストに存在するすべてのスレッドでその会話を操作できます。
同じプロセスの同じコンテキストで動作するアプリケーション・スレッドの場合、そのアプリケーション・スレッドがtpacall()の呼出し側かどうかに関係なく、tpgetrply()を呼び出して以前のtpacall()呼出しのレスポンスを受け取ることができます。
トランザクションをコミットまたは中断できるのは、同じプロセスの同じコンテキストに存在する1つのアプリケーション・スレッドだけです。トランザクションを開始したアプリケーション・スレッドである必要はありません。
すでにトランザクション・モードにあるコンテキストにtpbegin()を呼び出すことはできません。
XAトランザクションで構成されているグループにアプリケーション・サーバーが属している場合、tpopen()を呼び出してから、tpbegin()やSQL操作などのトランザクション・アクティビティを実行する必要があります。トランザクション操作を終了する場合は、tpclose()を呼び出す必要があります。
アプリケーション生成のサーバー・スレッドは、非請求メッセージを送信することはできますが、受信することはできません。
マルチコンテキスト・サーバーでのアプリケーション生成のサーバー・コンテキストにアプリケーション・スレッドを関連付けするためのサンプル・コード
リスト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);
}
 
関連項目
ATMIサーバーのアプリケーション生成スレッドのマルチスレッドとマルチコンテキストの動作
ATMIサーバーでのサーバー・ディスパッチ・スレッドのマルチスレッドとマルチコンテキストの動作
マルチスレッドATMIクライアントのコーディング
このトピックには次の項が含まれます:
注意:
Oracle Tuxedoシステムでは、COBOLアプリケーションのマルチスレッドはサポートされていません。
マルチスレッドATMIクライアントのコーディング規則
マルチスレッド・クライアントを使用する場合、コーディングで以下の規則に注意してください。
会話が開始されると、同じプロセス内のすべてのスレッドでその会話を操作できます。ハンドルと呼出し記述子は、同じプロセスの同じコンテキスト内で移植できます。ただし、ほかのコンテキストやプロセスには移植できません。ハンドルと呼出し記述子は、それらが元々割り当てられていたアプリケーション・コンテキストだけで使用できます。
同じプロセスの同じコンテキストで動作するスレッドの場合、そのスレッドがtpacall()の呼出し側かどうかに関係なく、tpgetrply()を呼び出して以前のtpacall()呼出しのレスポンスを受け取ることができます。
トランザクションをコミットまたは中断できるのは、1つのスレッドだけです。トランザクションを開始したスレッドである必要はありません。
すべてのRPC呼出しとすべての会話は、トランザクションをコミットする前に完了していなければなりません。未終了のRPC呼び出しや会話があるときにtpcommit()が呼び出されると、tpcommit()はトランザクションを中断し、-1を返してtperrno(5)TPEABORTを設定します。
トランザクションがまだコミットまたは中断していないことを確認できない場合に、tpcall()tpacall()tpgetrply()tpconnect()tpsend()tprecv()およびtpdiscon()などの関数をトランザクション・モードで呼び出すことはできません。
同じコンテキストに2つのtpbegin()呼出しを同時に行うことはできません。
すでにトランザクション・モードにあるコンテキストにtpbegin()を呼び出すことはできません。
クライアントを使用している場合に複数のドメインに接続するときは、TUXCONFIGまたはWSNADDRの値を手動で変更してからtpinit()を呼び出します。このような処理が複数のスレッドで行われる場合、環境変数の設定とtpinit()呼出しを同期する必要があります。クライアントのすべてのアプリケーション関連付けは、以下の規則に従う必要があります。
すべての関連付けは、同じリリースのOracle Tuxedoシステムに対して行われます。
特定のクライアントのすべてのアプリケーション関連付けはネイティブ・クライアントとして生成するか、またはワークステーション・クライアントとして生成します。
アプリケーションに参加するには、マルチスレッドのワークステーション・クライアントが、シングル・コンテキスト・モードで実行している場合でも、常にTPMULTICONTEXTSフラグを設定してtpinit()関数を呼び出す必要があります。
ATMIクライアントの複数のコンテキストへの初期化
クライアントを複数のコンテキストに参加させるには、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()を呼び出した結果生じるコンテキスト状態については、10-44ページの「マルチコンテキスト状態の遷移」を参照してください。
ATMIクライアント・スレッドのコンテキスト状態の変化
マルチコンテキストのアプリケーションでは、いろいろな関数を呼び出すと、呼出し側スレッド、および呼出し側プロセスと同じコンテキストでアクティブなその他のスレッドのコンテキスト状態が変化します。図10-4は、tpinit()tpsetctxt(3c)およびtpterm()を呼び出した結果、変化したコンテキスト状態を示しています。(tpgetctxt(3c)関数を呼び出しても、コンテキスト状態は変化しません。)
 
図10-4 マルチコンテキスト状態の遷移
注意:
tpterm()がマルチコンテキスト状態(TPMULTICONTEXTS)で実行しているスレッドによって呼び出されると、呼出し側スレッドはNULLコンテキスト状態(TPNULLCONTEXT)になります。終了するコンテキストに関連するその他すべてのスレッドは、無効コンテキスト状態(TPINVALIDCONTEXT)に切り替わります。
次の図は、tpinit()tpsetctxt(3c)およびtpterm()を呼び出した結果、変化したコンテキスト状態を示しています。
 
表10-2 クライアント・スレッドのコンテキスト状態の変化
この関数が実行されるとき...
このコンテキスト状態のスレッドの結果は...
NULLコンテキスト
シングル・コンテキスト
マルチコンテキスト
無効コンテキスト
TPMULTICONTEXTSが設定されていないtpinit()
シングル・コンテキスト
シングル・コンテキスト
エラー
エラー
TPMULTICONTEXTSが設定されたtpinit()
マルチコンテキスト
エラー
マルチコンテキスト
エラー
TPNULLCONTEXTtpsetctxt(3c)
Null
エラー
Null
Null
context 0のtpsetctxt(3c)
エラー
シングル・コンテキスト
エラー
エラー
context > 0のtpsetctxt(3c)
マルチコンテキスト
エラー
マルチコンテキスト
マルチコンテキスト
暗黙的なtpinit()
シングル・コンテキスト
なし
なし
エラー
このスレッド内のtpterm()
Null
Null
Null
Null
このコンテキストの別のスレッド内のtpterm()
なし
Null
無効
なし
マルチスレッド環境での応答の取得
tpgetrply()は、tpacall()からのリクエストに対するレスポンスだけを受け取ります。tpcall()からのリクエストは、マルチスレッドまたはマルチコンテキストのレベルに関係なく、tpgetrply()で取得することはできません。
tpgetrply()は、1つのコンテキスト、つまりtpgetrply()の呼出し側コンテキストだけで動作します。そのため、TPGETANYフラグを設定してtpgetrply()を呼び出すと、同じコンテキストで生成されたハンドルだけが考慮されます。同じように、あるコンテキストで生成されたハンドルを別のコンテキストで使用することはできません。ただし、同じコンテキストで動作するスレッドには、そのハンドルを使用できます。
tpgetrply()をマルチスレッド環境で呼び出す場合、次の制約があります。
1つのスレッドがすでにtpgetrply()で特定のハンドルを待機しているときに、同じコンテキストの別のスレッドがtpgetrply()を呼び出して同じハンドルの取得を試みると、tpgetrply()-1を返し、tperrnoTPEPROTOを設定します。
1つのスレッドがすでにTPGETANYフラグを設定してtpgetrply()の応答を待機しているときに、同じコンテキストの別のスレッドがtpgetrply()を呼び出して特定のハンドルの取得を試みると、tpgetrply()は-1を返し、tperrno(5)TPEPROTOを設定します。
これは、1つのスレッドがすでにtpgetrply()で特定のハンドルを待機しているときに、同じコンテキストの別のスレッドがTPGETANYフラグを設定してtpgetrply()を呼び出した場合も同じです。これらの制約により、特定のハンドルを待機しているスレッドがある場合、その応答が別のスレッドに渡されることがなくなります。
ある時点で、TPGETANYフラグを設定してtpgetrply()の応答を待機できるのは、特定のコンテキスト内で1つのスレッドだけです。TPGETANYフラグを設定して呼び出したtpgetrply()がまだ処理されていない場合に、同じコンテキストの別のスレッドが同じ呼出しを行うと、この2番目の呼出しは-1を返してtperrno(5)TPEPROTOに設定します。
マルチスレッド・マルチコンテキスト環境の環境変数の使用
Oracle Tuxedoアプリケーションをマルチコンテキスト・マルチスレッド環境で実行する場合、環境変数に関して以下の事柄に注意してください。
プロセスは、初期状態ではその環境をオペレーティング・システム環境から継承します。環境変数がサポートされているプラットフォームでは、そのような変数はプロセス単位で動作するエンティティを構成します。そのため、コンテキスト単位の環境設定に依存するアプリケーションでは、オペレーティング・システム関数ではなくtuxgetenv(3c)関数を使用する必要があります。
注意:
オペレーティング・システム環境が認識されないオペレーティング・システムの場合、初期状態では空の環境になっています。
多くの環境変数は、Oracle Tuxedoシステムでプロセスごとに1回、またはコンテキストごとに1回だけ読み取られ、Oracle Tuxedoシステム内にキャッシュされます。プロセスに一度キャッシュされた変数を変更しても影響はありません。
 
キャッシュ処理は次で行われます...
次の環境変数に対して...
コンテキスト単位
TUXCONFIG
FIELDTBLSおよびFIELDTBLS32
FLDTBLDIRおよびFLDTBLDIR32
ULOGPFX
VIEWDIRおよびVIEWDIR32
VIEWFILESおよびVIEWFILES32
WSNADDR
WSDEVICE
WSENV
プロセス単位
TMTRACE
TUXDIR
ULOGDEBUG
tuxputenv(3c)関数はプロセス全体の環境に影響します。
tuxreadenv(3c)関数を呼び出すと、環境変数を含むファイルが読み取られ、それらの変数がプロセス全体の環境に追加されます。
tuxgetenv(3c)関数は、現在のコンテキストで要求された環境変数の現在の値を返します。初期設定では、すべてのコンテキストが同じ環境になります。ただし、特定のコンテキストに固有の環境ファイルを使用すると、コンテキストごとに異なる環境設定を持つことができます。
クライアントが複数のドメインに初期化する場合、tpinit()を呼び出す前に、毎回TUXCONFIGWSNADDR、またはWSENVFILE環境変数の値を適切な値に変更する必要があります。そのようなアプリケーションがマルチスレッドの場合、以下の処理を確実に行うために、ミューテックスなどのアプリケーション定義の同時実行性制御が必要になります。
適切な環境変数が再設定されること
他のスレッドによって環境変数が再設定されずにtpinit()が呼び出されること
クライアントがシステムに初期化する場合、WSENVFILEやマシン環境ファイルが読み取られ、そのコンテキストの環境だけが影響を受けます。環境ファイルでオーバーライドされないコンテキスト部分には、プロセス全体に対する以前の環境が適用されます。
マルチスレッドATMIクライアントでのコンテキスト単位の関数とデータ構造体
以下に示すATMI関数は、呼出し側のアプリケーション・コンテキストだけに影響します。
tpopen(3c)
注意:
tpbroadcast()の場合、ブロードキャスト・メッセージは特定のアプリケーションとの関連付けから送られたものとして識別されます。tpnotify(3c)の場合、通知は特定のアプリケーションとの関連付けから送られたものとして識別されます。tpinit()の注記については、「マルチスレッド・クライアントでのプロセス単位の関数とデータ構造体」を参照してください。
tpsetunsol()がコンテキストに関連付けされていないスレッドから呼び出されると、新しく生成されるすべてのtpinit()コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ・ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときにtpsetunsol()を再度呼び出して、そのコンテキストの非請求メッセージ・ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ・ハンドラは、コンテキストに現在関連付けされていないスレッドでtpsetunsol()を再度呼び出すと、変更できます。
CLIENTID、クライアント名、ユーザー名、トランザクションID、およびTPSVCINFOデータ構造体の内容は、同じプロセス内のコンテキストによって異なる場合があります。
非同期呼出しハンドルと接続記述子は、その生成元コンテキスト内で有効です。任意通知のタイプは、コンテキストごとに固有です。シグナル・ベースの通知はマルチコンテキストでは使用できませんが、各コンテキストでは次のいずれかのオプションを使用できます。
非請求メッセージの無視
ディップ・イン通知の使用
専用のスレッド通知の使用
マルチスレッドATMIクライアントでのプロセス単位の関数とデータ構造体
以下に示すOracle Tuxedo関数は、呼出し側のプロセス全体に影響します。
tpconvert(3c) - リクエストされた構造体が変換されます。ただし、プロセスのサブセットのみに対応します。
tpinit() - プロセス単位のTPMULTICONTEXTSモードまたはシングル・コンテキスト・モードに応じて適用されます。10-48ページの「マルチスレッドATMIクライアントでのコンテキスト単位の関数とデータ構造体」も参照してください。
tuxgetenv(3c) - オペレーティング・システム環境がプロセス単位の場合。
tuxputenv(3c) - オペレーティング・システム環境がプロセス単位の場合。
tuxreadenv(3c) - オペレーティング・システム環境がプロセス単位の場合。
シングル・コンテキスト・モード、マルチコンテキスト・モード、または非初期化モードのどれを使用するかは、プロセス全体に影響します。また、バッファ・タイプ・スイッチ、ビュー・キャッシュ、および環境変数の値も、プロセス単位の関数です。
マルチスレッドATMIクライアントでのスレッド単位の関数とデータ構造体
以下に示す関数は、呼出し側のスレッドだけに影響します。
CATCH
Ferror、Ferror32(5)tperrno(5)tpurcode(5)およびUunix_err変数は、各スレッドに固有です。
現在のコンテキストのIDは各スレッドに固有です。
マルチスレッドATMIクライアントのサンプル・コード
リスト10-5は、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));
       /*
        * This code will perform a transfer, using separate threads for the
        * withdrawal and deposit. It will also get the current
        * price of Oracle 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 Oracle 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サーバーのコーディング
ほとんどの場合、マルチスレッド・サーバーはマルチコンテキストでもあります。マルチスレッドATMIサーバーのコーディングについては、10-34ページの「ATMIサーバーでサーバー・ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング」を参照してください。
マルチスレッド/マルチコンテキスト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()-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システムにアクセスするスレッドには、最低512 Kを指定してください。
Compaq Tru64 UNIXおよびPOSIXスレッドが使用されるそのほかのシステムでは、スレッドのスタック・サイズは、pthread_create()を呼び出す前にpthread_attr_setstacksize()を呼び出して指定します。UnixWareでは、スレッドのスタック・サイズはthr_create()の引数として指定されます。この問題の詳細は、お使いのオペレーティング・システムのドキュメントを参照してください。
マルチスレッド/マルチコンテキストATMIアプリケーションのエラー処理
エラーはユーザー・ログに記録されます。シングル・コンテキスト・モードでもマルチコンテキスト・モードでも、各エラーに対して次の情報が記録されます。
process_ID.thread_ID.context_ID
関連項目

Copyright ©1994, 2017,Oracle and/or its affiliates. All rights reserved