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

     前  次    新規ウィンドウで目次を開く    PDFとして表示 - 新規ウィンドウ  Adobe Readerを入手 - 新規ウィンドウ
コンテンツはここから始まります

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

このトピックには次の項が含まれます:

 


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

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

お使いのオペレーティング・システムで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つのサーバー・プロセスによる複数のサービス・スレッドのディスパッチ

マルチコンテキストとは

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

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

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

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

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

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

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

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

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

関連項目

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

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

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

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

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

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

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

関連項目

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

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

起動フェーズ

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

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

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

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

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

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

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

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

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

目的のコンテキストとの関連付けが確立されると、2番目のスレッドはコンテキスト単位で動作するATMI関数を使用してタスクを実行できるようになります。詳細は、「マルチスレッド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()が呼び出される前に、すべてのスレッドが同期していなければなりません。

関連項目

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つのサーバーに、設定可能な最大数まで複数のスレッドを生成します。サーバーが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)が呼び出されて、リソース・マネージャのクローズなど、必要な終了処理が行われます。

関連項目

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

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

アプリケーション生成のサーバー・スレッドは別の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ドメインでは正しく動作しますが、すべてのドメインで正しく動作するとはかぎりません。そのようなアプリケーションを作成する場合、次の事項について検討する必要があります。

環境の要件

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

設計の要件

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

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

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

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

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

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

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

同期に関する検討事項

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

アプリケーションの移植

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

最適なスレッド・モデル

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

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

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

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

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

関連項目

 


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

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

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

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

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

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

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

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

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

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

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

関連項目

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

この項には次のトピックが含まれます:

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

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

コンテキストの属性

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

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

クライアントがアプリケーションに参加する準備ができたら、リスト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()を呼び出し、最初のアプリケーションに参加します。
  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アプリケーションにおけるトランザクションのコーディング規則

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

関連項目

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

このトピックには次の項が含まれます:

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

コンテキストの属性

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

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

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

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

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

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

関連項目

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

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

このトピックには次の項が含まれます:

スレッドの生成

オペレーティング・システムのスレッド関数を使用して、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);
}

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

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

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

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

リスト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クライアントのコーディング規則

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

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()を呼び出した結果生じるコンテキスト状態については、「マルチコンテキスト状態の遷移」を参照してください。

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()
マルチコンテキスト
エラー
マルチコンテキスト
エラー
TPNULLCONTEXTへのtpsetctxt(3c)
NULL
エラー
NULL
NULL
コンテキスト0へのtpsetctxt(3c)
エラー
シングル・コンテキスト
エラー
エラー
コンテキスト> 0へのtpsetctxt(3c)
マルチコンテキスト
エラー
マルチコンテキスト
マルチコンテキスト
暗黙的なtpinit()
シングル・コンテキスト
N/A
N/A
エラー
このスレッドでのtpterm()
NULL
NULL
NULL
NULL
このコンテキストの異なるスレッドでのtpterm()
N/A
NULL
無効
N/A

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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サーバーのコーディングについては、「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

関連項目


  先頭に戻る       前  次