|
Oracle Tuxedo システムでは、次のアプリケーションがサポートされています。
お使いのオペレーティング システムで POSIX スレッド関数と共にほかのスレッド関数がサポートされている場合は、POSIX スレッド関数を使用することをお勧めします。この関数を使用すると、後でコードをほかのプラットフォームに簡単に移植できます。
お使いのプラットフォームでカーネルレベルのスレッド パッケージ、C 言語の関数、または POSIX 関数がサポートされているかどうかを確認するには、『Oracle Tuxedo システムのインストール』の「Oracle Tuxedo 10g リリース 3 (10.3) プラットフォーム データ シート」で、使用しているオペレーティング システムのデータ シートを参照してください。
多くのプラットフォームには、マルチスレッドおよびマルチコンテキスト アプリケーション固有の要件があります。プラットフォーム固有の要件については、『Oracle Tuxedo システムのインストール』の「Oracle Tuxedo 10g リリース 3 (10.3) プラットフォーム データ シート」に説明があります。お使いのプラットフォームの要件については、該当するデータシートを参照してください。
Oracle Tuxedo システムでは、単一のプロセスで複数のタスクを同時に実行できます。このようなプロセスを実装するプログラミング手法はマルチスレッドおよびマルチコンテキストと呼ばれます。この節では、これらの手法に関する基本事項について説明します。
マルチスレッドとは、1 つのプロセスに複数の実行単位が含まれている処理方法です。マルチスレッド アプリケーションでは、同じプロセスから同時に複数の呼び出しを行うことができます。たとえば、個々のプロセスが 1 つの未終了の tpcall() に制限されることはありません。
サーバのマルチスレッドでは、アプリケーション生成のスレッドがシングルコンテキスト サーバで使用される場合を除き、マルチコンテキストが必要です。マルチスレッドのシングルコンテキスト アプリケーションを作成する唯一の方法は、アプリケーション生成のスレッドを使用することです。
Oracle Tuxedo システムでは、C 言語で記述されたマルチスレッド アプリケーションがサポートされています。COBOL 言語のマルチスレッド アプリケーションはサポートされていません。
次の図は、マルチスレッド クライアントが 3 つのサーバに対して同時に呼び出しを行う方法を示しています。
マルチスレッド アプリケーションでは、同じサーバで複数のサービス ディスパッチ スレッドを使用できるので、アプリケーションに対して起動するサーバ数が少なくて済みます。
次の図は、異なるクライアントに対して、サーバ プロセスが同時に複数のスレッドをディスパッチする方法を示しています。
コンテキストはドメインへの対応付けです。マルチコンテキストを使用すると、1 つのプロセスで次のいずれかが可能になります。
マルチコンテキストは、クライアントとサーバの両方で使用できます。サーバでマルチコンテキストを使用すると、マルチスレッドも使用することになります。
コンテキストの特徴の詳細については、次のいずれかの節で「コンテキストの属性」を参照してください。
Oracle Tuxedo システムでは、C 言語または COBOL 言語のいずれかで記述されたマルチコンテキスト アプリケーションがサポートされています。ただし、サポートされるマルチスレッド アプリケーションは、C 言語で記述されたものだけです。
次の図は、ドメイン内でのマルチコンテキスト クライアント プロセスの動作を示しています。矢印はサーバへの未終了の呼び出しを表します。
各コンテキストは 1 人のユーザとしてカウントされます。以下に例を示します。
マルチスレッドとマルチコンテキストを適切な状況で使用すると、Oracle Tuxedo アプリケーションのパフォーマンスを向上できます。ただし、これらの手法を取り入れる前に、潜在的な利点と問題点について理解しておくことが大切です。
マルチスレッドおよびマルチコンテキスト アプリケーションには、以下の利点があります。
マルチスレッドとマルチコンテキストを併用すると、一部のアプリケーションではパフォーマンスと同時実行性が向上します。また、一部のアプリケーションでは、パフォーマンスが変わらないか、逆に低下する場合があります。パフォーマンスへの影響は、使用しているアプリケーションによって異なります。
アプリケーションによっては、異なるリモート プロシージャ コールと会話を別々のスレッドでコーディングした方が、同じスレッドで管理するより簡単な場合があります。
Oracle Tuxedo クライアントを同時に複数のアプリケーションに接続できます。
1 つのサーバで複数のサービス スレッドをディスパッチできるので、アプリケーションに対して起動するサーバの数を減らすことができます。このように複数のスレッドをディスパッチできる機能は、特に会話型サーバの場合に有用です。会話型サーバにこの機能がない場合、会話が終了するまで 1 つのクライアントしか使用できなくなります。
アプリケーションで、クライアント スレッドが Microsoft Internet Information Server API または Netscape Enterprise Server インタフェース (NSAPI) によって生成される場合、これらのツールの機能を最大限に利用するにはマルチスレッドが不可欠です。ほかのツールについても同じことが言えます。
マルチスレッドおよびマルチコンテキスト アプリケーションには、以下の問題点があります。
マルチスレッドおよびマルチコンテキスト アプリケーションのコーディングは簡単ではありません。このようなアプリケーションのコーディングは、十分な経験を持つプログラマだけが行うことができます。
マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションで発生したエラーを再現することは、シングルスレッドおよびシングルコンテキスト アプリケーションで再現するより難しい作業です。そのため、エラー発生時にその根本的な原因を特定して検証することがさらに難しくなります。
スレッド間の同時実行性の管理は難しい作業であり、アプリケーションで新たに問題を引き起こす可能性があります。
マルチスレッド アプリケーションのテストは、シングルスレッド アプリケーションのテストより難しい作業です。問題がタイミングに関連していることが多く、再現が困難だからです。
既存のコードでマルチスレッドとマルチコンテキストを使用するには、大部分のコードを再構築しなければなりません。プログラマは、以下の作業を行う必要があります。
マルチスレッドおよびマルチコンテキスト アプリケーションがアクティブの場合、クライアントのライフサイクルは次の 3 つのフェーズから構成されます。
注意 : | Oracle Tuxedo システムから独立して動作するスレッドが存在する場合もあります。ここでは、そのようなスレッドについては説明していません。 |
Oracle Tuxedo マルチコンテキスト アプリケーションのクライアントは、次の規則に従う限り、複数のアプリケーションに対応付けることができます。
クライアントが複数のコンテキストに参加するには、TPINFO
データ型の flags
要素に TPMULTICONTEXTS
フラグを設定して、tpinit() 関数を呼び出します。
TPMULTICONTEXTS
フラグを設定して tpinit()
関数が呼び出されると、アプリケーションとの新しい対応付けが生成され、スレッドに対するカレントの対応付けが指定されます。新しい対応付けが生成される Oracle Tuxedo ドメインは、TUXCONFIG
または WSENVFILE/WSNADDR
環境変数の値で決定されます。
多くの ATMI 関数はコンテキスト単位で動作します。このような ATMI 関数のリストについては、「マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。コンテキスト単位で動作するには、対象コンテキストが現在のコンテキストであることが必要です。クライアントは複数のコンテキストに参加できますが、状況とスレッドにかかわらず現在のコンテキストになることができるコンテキストは 1 つだけです。
アプリケーション内でタスクの優先順位が移り、ほかの Oracle Tuxedo ドメインと通信する必要が発生した場合、あるコンテキストから別のコンテキストにスレッドを再割り当てした方がよい場合があります。
そのような場合、あるクライアント スレッドが tpgetctxt(3c) を呼び出し、返された現在のコンテキストを値として持つハンドルを別のクライアント スレッドに渡します。2 番目のスレッドは tpsetctxt(3c) を呼び出し、最初のスレッドで tpgetctxt(3c) から受け取ったハンドルを指定して、現在のコンテキストとの対応付けを確立します。
目的のコンテキストとの対応付けが確立されると、2 番目のスレッドはコンテキスト単位で動作する ATMI 関数を使用してタスクを実行できるようになります。詳細については、「マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体」を参照してください。
このフェーズでは、各スレッドによって処理が行われます。次は、行われる処理の例です。
スレッドは、同期要求の場合は tpcall()、非同期要求の場合は tpacall() を呼び出して、サーバに要求を送ります。tpcall()
で要求を送った場合、以降操作を行わなくても応答を受け取ることができます。
tpacall() でサービスの非同期要求を送った場合、同じコンテキスト内のスレッドは tpgetrply() を呼び出して応答を受け取ります。このスレッドは、要求を送ったスレッドと同じスレッドではない場合もあります。
あるスレッドがトランザクションを開始すると、そのスレッドのコンテキストを共有するすべてのスレッドでそのトランザクションが共有されます。
コンテキスト内の多くのスレッドでトランザクションに関する処理が行われますが、トランザクションをコミットまたはアボートできるのは 1 つのスレッドだけです。トランザクションをコミットまたはアボートするスレッドは、トランザクションを開始したスレッドである必要はなく、トランザクションを処理しているどのスレッドでもかまいません。スレッド アプリケーションでは、通常のトランザクション規則に従うために、適切に同期を行う必要があります。たとえば、未終了の RPC 呼び出しや会話がある場合に、トランザクションをコミットすることはできません。また、トランザクションがコミットまたはアボートされた後で、そのトランザクションに対する呼び出しを行うことはできません。プロセスは、アプリケーションの各対応付けに対して、1 つのトランザクションの一部にだけなることができます。
アプリケーションの 1 つのスレッドが tpcommit() を呼び出し、それと同時に別のスレッドが RPC 呼び出しまたは会話型呼び出しを行うと、これらの呼び出しは特定の順序で呼び出されたものとして処理されます。アプリケーション コンテキストは、シングルスレッド プログラムとシングルコンテキスト プログラムに対する制約と同じ制約に従って、tpsuspend() を呼び出してトランザクションを一時的に中断し、別のトランザクションを開始します。
マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションの各コンテキストでは、非請求メッセージを次の 3 種類のいずれかの方法で処理できます。
専用のスレッド通知の場合、非請求メッセージの受信と、非請求メッセージ ハンドラのディスパッチに別々のスレッドが使用されます。あるコンテキストで一度に実行できる非請求メッセージ ハンドラは 1 つだけです。
スレッドがサポートされていない Oracle Tuxedo システム用プラットフォームで tpinit() が呼び出された場合に、スレッドがサポートされていないプラットフォーム上で TPU_THREAD
通知が要求されたことを示すパラメータが指定されていると、tpinit()
は -1
を返して tperrno
に TPEINVAL
を設定します。UBBCONFIG(5) のデフォルトの NOTIFY
オプションが THREAD
に設定されている場合に、特定のマシンでスレッドを利用できないと、そのマシンのデフォルトの機能は DIPIN
になります。このような動作の相違があるので、スレッドがサポートされているマシンとサポートされていないマシンが混在するコンフィグレーションでは、管理者はすべてのマシンにデフォルトを指定できます。ただし、そのマシンで利用できない機能をクライアントが明示的に要求することはできません。
tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol()
を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol()
を再度呼び出すと、変更できます。
プロセスが同じアプリケーションと複数の対応付けを持つ場合、各対応付けに異なる CLIENTID
を割り当てられ、非請求メッセージを特定のアプリケーションとの対応付けに送信できるようになります。プロセスが同じアプリケーションと複数の対応付けを持つ場合、ブロードキャスト基準を満たすアプリケーションの各対応付けに任意の tpbroadcast() が別々に送信されます。非請求メッセージを受信する場合のディップ イン チェックでは、カレントのアプリケーションとの対応付けに送信されるメッセージだけが対象となります。
非請求メッセージ ハンドラでは ATMI 関数を利用できるほか、非請求メッセージ ハンドラ内で tpgetctxt(3c) を呼び出すことができます。そのため、非請求メッセージ ハンドラは別のスレッドを生成して、同じコンテキスト内で必要となる実質的な ATMI 作業を行うことができるようになります。
userlog(3c) を使用すると、各アプリケーション内の各スレッドに対して次の識別情報が記録されます。
process_ID.thread_ID.context_ID
スレッドがサポートされていないプラットフォームやシングルコンテキスト アプリケーションに対しては、エントリの thread_ID
フィールドと context_ID
フィールドにプレースホルダが出力されます。
TM_MIB(5) では、この機能は T_ULOG
クラスの TA_THREADID
フィールドと TA_CONTEXTID
フィールドでサポートされています。
このフェーズでは、クライアント プロセスの終了時に、カレントのコンテキストおよび対応付けられたすべてのスレッドに代わって 1 つのスレッドが tpterm() を呼び出してそのアプリケーションとの対応付けを終了します。ほかの ATMI 関数と同じように、tpterm()
は現在のコンテキストに対して処理を行います。tpterm() は、終了するコンテキストに対応付けされたすべてのスレッドに影響し、これらのスレッドで共有されるすべてのコンテキストを終了します。
アプリケーションの設計が適切であれば、特定のコンテキスト内のすべての処理が完了してから tpterm()
が呼び出されます。tpterm()
が呼び出される前に、すべてのスレッドが同期していなければなりません。
マルチスレッドおよびマルチコンテキスト アプリケーションがアクティブの場合、サーバで行われる処理は次の 3 つのフェーズに分類できます。
起動フェーズで行われる処理は、コンフィグレーション ファイルの MINDISPATCHTHREADS
と MAXDISPATCHTHREADS
パラメータの値によって異なります。
クライアントのサービス要求への応答として、サーバ ディスパッチャは設定可能な最大数まで複数のスレッドを 1 つのサーバに生成します。このサーバは、各種のクライアント要求に同時に割り当てることができます。サーバが tpinit() を呼び出すことはできません。
各ディスパッチ スレッドは、別々のコンテキストと対応付けられています。この機能は会話型サーバと RPC サーバの両方で有用です。特に、会話型サーバではこの機能を利用できないと、ほかの会話接続がサービスを待っている間、クライアント サイドの会話をアイドル状態で待つことになります。
この機能は、UBBCONFIG(5) ファイルの SERVERS
セクションと TM_MIB(5) の次のパラメータで制御されます。
THREADSTACKSIZE
または TA_THREADSTACKSIZE
で指定されるスタック サイズで生成されます。このパラメータが指定されていない場合、または 0 の場合、オペレーティング システムのデフォルト値が使用されます。オペレーティング システムのデフォルト値が小さすぎて Oracle Tuxedo システムで使用できない場合、その値より大きなデフォルト値が使用されます。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 はタイムアウト値を超えてメッセージの受信を待機しているプロセスまたはスレッドにメッセージを送信します。すると、ブロッキング メッセージ受信への呼び出しが、タイムアウトを示すエラーを返します。
Oracle Tuxedo システムでは、各サーバに対して次の統計情報が保持されます。
userlog(3c) を使用すると、各アプリケーション内の各スレッドに対して次の識別情報が記録されます。
process_ID.thread_ID.context_ID
スレッドがサポートされていないプラットフォームやシングルコンテキスト アプリケーションに対しては、エントリの thread_ID
フィールドと context_ID
フィールドにプレースホルダが出力されます。
TM_MIB(5) では、この機能は T_ULOG
クラスの TA_THREADID
フィールドと TA_CONTEXTID
フィールドでサポートされています。
アプリケーションを停止すると、tpsvrthrdone(3c) と tpsvrdone(3c) が呼び出されて、リソース マネージャのクローズなど、必要な終了処理が行われます。
オペレーティング システム関数を使用して、Tuxedo アプリケーション サーバ内に新しいスレッドを追加できます。最初、アプリケーション生成サーバ スレッドは、どの Tuxedo コンテキストにも関連していません。アプリケーション生成のスレッドは、次のように動作します。
tpappthrinit(3c)
によって生成されたコンテキストで動作します (この機能は、Tuxedo 10g リリース 3 (10.3) で利用できます)。
この状況では、アプリケーション生成のサーバ スレッドは tpsetctxt(3c)
を呼び出し、サーバ ディスパッチ スレッド内の以前の tpgetctxt(3c)
呼び出しによって返される値を渡して、サーバ ディスパッチ コンテキストとの対応付けを確立します。
サーバ ディスパッチ コンテキストに対応付けられたアプリケーション生成のサーバ スレッドは、処理が終了したら、元のディスパッチ スレッドが tpreturn()
を呼び出す前に、tpsetctxt(3c)
を呼び出して TPNULLCONTEXT
に設定する必要があります。
tpreturn()
および tpforward()
を呼び出すことはできません。
アプリケーション生成のサーバ スレッドは別の Tuxedo コンテキストを生成し、tpappthrinit(3c)
を使用してこのコンテキストに自身を対応付けることができます。アプリケーション生成のサーバ スレッドがアクティブな場合、tpappthrinit(3c)
によって生成された Tuxedo コンテキストのライフサイクルは、次の 3 つのフェーズから構成されます。
アプリケーション生成のサーバ スレッドは Tuxedo コンテキストを生成し、tpappthrinit(3c)
を呼び出すことによってこのコンテキストに自身を対応付けます。tpappthrinit(3c)
によって生成されたコンテキストは、アプリケーション サーバが存在するドメインに接続します。
必要に応じて、tpappthrinit(3c)
を正常に呼び出した後、サーバ内のアプリケーション生成のスレッドが tpgetctxt(3c)
を呼び出し、返されるハンドル (現在のコンテキストの値) を同じプロセス内の別のアプリケーション スレッドに渡します。
各アプリケーション生成のサーバ スレッドによって、次の処理が行われます。
アプリケーション生成のサーバ スレッドで実行されるこれらの処理は、クライアント プログラムの場合と同様の特徴を持っています。詳細については、「クライアントでのマルチスレッドとマルチコンテキストの動作」を参照してください。
注意: | アプリケーション生成のサーバ スレッドは、tpreturn() および tpforward() を呼び出すことはできません。 |
アプリケーション生成のサーバ スレッドは、非請求メッセージを送信することはできますが、受信することはできません。
userlog(3c)
を使用すると、サーバの各アプリケーション生成スレッドに対する識別情報 (process_ID.thread_ID.context_ID
) が記録されます。
TM_MIB(5)
では、この機能は T_ULOG
クラスの TA_THREADID
フィールドと TA_CONTEXTID
フィールドでサポートされています。
アプリケーション生成のサーバ スレッドは処理が終了すると、tpappthrterm(3c)
を呼び出して現在のコンテキストを終了します。
tpappthrterm(3c)
は、同じコンテキストで現在動作しているすべてのアプリケーション生成のサーバ スレッドに影響を与えます。終了されるコンテキストでほかのアプリケーション生成のサーバ スレッドが動作している場合は、tpappthrterm(3c)
を呼び出さないようにしてください。
アプリケーションの設計が適切であれば、特定のコンテキスト内のすべての処理が完了してから tpappthrterm(3c)
が呼び出されます。アプリケーション スレッドが tpappthrterm(3c)
を呼び出す前に、すべてのアプリケーション スレッドが同期しているかを確認してください。
マルチスレッドおよびマルチコンテキスト アプリケーションの設計上の検討事項
サーバのアプリケーション生成スレッドでマルチコンテキストを使用するためのコーディング
サーバでサーバ ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング
マルチスレッドおよびマルチコンテキスト アプリケーションは、一部の Oracle Tuxedo ドメインでは正しく動作しますが、すべてのドメインで正しく動作するとは限りません。そのようなアプリケーションを作成する場合、次の事項について検討する必要があります。
マルチスレッド アプリケーションまたはマルチコンテキスト アプリケーションの開発では、開発環境と実行時環境に関して次の内容を検討します。
OPENINFO
文字列の一部として THREADS=true
パラメータを設定する必要があります。この設定により、各スレッドが Oracle との別々の対応付けとして動作するようになります。
すべての RM で混在モードがサポートされているわけではありません。プロセス内のすべてのスレッドが同じ RM との対応付けにマップされなければならない場合もあります。アプリケーション生成のスレッド内でトランザクションに関与する RM アクセスを使用するアプリケーションを設計する場合は、RM で混在モードがサポートされていることを確認します。
マルチスレッド アプリケーションやマルチコンテキスト アプリケーションの設計では、次の内容を検討します。
次の表は、アプリケーションをマルチスレッドまたはマルチコンテキストにすべきかどうかを判断するための参考となる検討事項を示しています。この表だけでは十分ではないので、個々の要件に基づいてほかの事項も検討してください。
そのほかの検討事項については、マルチスレッド アプリケーションやマルチコンテキスト アプリケーションのプログラミングに関する書籍を参照してください。
アクセスするアプリケーションの数と、確立する接続の数を決定します。
これは設計段階での重要な検討事項です。このマニュアルでは、この内容について取り上げていません。マルチスレッド アプリケーションやマルチコンテキスト アプリケーションのプログラミングに関する書籍を参照してください。
後でアプリケーションを移植する必要がある場合、オペレーティング システムに応じて異なる関数が使用されていることに注目してください。あるプラットフォームで作成した初期バージョンのアプリケーションを後で移植する場合、異なる関数でコードを書き直すためにどれだけのリソース時間が必要なのかを考慮する必要があります。
現在使用されているマルチスレッド プログラムには、次のようなモデルがあります。
スレッド モデルについては、このマニュアルでは取り上げていません。アプリケーションのプログラミング モデルを選択する場合は、利用できるすべてのモデルを調べて、設計の要件を慎重に検討してください。
リリース 7.1 の Workstation クライアントと 7.1 以前の Oracle Tuxedo システムに基づくアプリケーションとの相互運用性は、次のどの場合でもサポートされています。
Oracle Tuxedo リリース 7.1 のワークステーション クライアントで、1 つのコンテキストに複数のスレッドがある場合は、リリース 7.1 より前の Oracle Tuxedo システムとは相互運用しません。
コーディングを開始する前に、次の内容や条件を満たしていることを確認してください。
開発プロジェクトを開始する前に、開発環境が次の条件を満たしていることを確認します。
Oracle Tuxedo システムには、スレッド生成用のツールは提供されていません。ただし、ほかのオペレーティング システムで提供される各種のスレッド パッケージがサポートされています。スレッドを生成して同期するには、オペレーティング システム固有の関数を使用する必要があります。オペレーティング システムでサポートされているスレッド パッケージを確認するには、『Oracle Tuxedo システムのインストール』の「Oracle Tuxedo 10g リリース 3 (10.3) プラットフォーム データ シート」を参照してください。
マルチスレッド プログラムは、十分に経験を持つプログラマがコーディングします。特に、次のようなマルチスレッド固有の設計に関する基本的な知識があることが必要です。
これらは検討事項の一部にすぎず、ここに記せないほど多くの検討事項があります。マルチスレッド プログラムをコーディングするプログラマは、それらの検討事項を熟知していることが前提となります。これらの検討事項については、マルチスレッド アプリケーションのプログラミングに関する書籍を参照してください。
マルチスレッドを使用すると、1 つのアプリケーションの異なるスレッドが同じ会話で並列処理を行うことができるようになります。この方法はお勧めしませんが、Oracle Tuxedo システムで禁止されているわけではありません。異なるスレッドによって同じ会話で並列処理が行われると、システムは同時呼び出しが任意の順序で行われたように動作します。
複数のスレッドを使ってプログラミングする場合、ミューテックスなどの同時実行性制御関数を使用して、スレッド間の同時実行性を管理する必要があります。以下は、同時実行性制御が必要になる 3 つの例です。
tpcommit()
が呼び出される場合、アプリケーションで何らかの同時実行性制御が必要になります。 tpsend()
呼び出しが任意の順序で行われたように動作します。アプリケーション プログラマは、それを認識しておかなければなりません。
ほとんどのアプリケーションで最良の方法は、1 つの会話のすべての処理を 1 つのスレッドにまとめてコーディングすることです。また、同時実行性制御を使用して、これらの処理を連続して行う方法もあります。
アプリケーションでトランザクションを使用する場合、トランザクションのマルチコンテキストの結果についても注目します。詳細については、「マルチスレッドおよびマルチコンテキスト アプリケーションにおけるトランザクションのコーディング規則」を参照してください。
注意 : | この節で示す手順とサンプル コードは、Oracle Tuxedo システムで提供される C 言語のライブラリ関数を参照します。それらに相当する COBOL ライブラリ関数も利用できます。詳細については、『Tuxedo COBOL リファレンス』を参照してください。 |
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
TPNULLCONTEXT
に変更されることはありません。tpinit()
を呼び出すたびに、確立されているセキュリティ メカニズムを調整する必要があります。
クライアントがアプリケーションに参加する準備ができたら、次のサンプル コードに示すように、TPMULTICONTEXTS
フラグを設定して tpinit() を指定します。
#include <stdio.h>
#include <atmi.h>
TPINIT * tpinitbuf;
main()
{
tpinitbuf = tpalloc(“TPINIT”, NULL, TPINITNEED(0));
tpinitbuf->flags = TPMULTICONTEXTS;
.
.
.
if (tpinit (tpinitbuf) == -1) {
ERROR_PROCESSING_CODE
}
.
.
.
}
新しいアプリケーションとの対応付けが生成され、TUXCONFIG
または WSENVFILE/WSNADDR
環境変数で指定された Oracle Tuxedo ドメインに割り当てられます。
注意 : | 1 つのプロセスでは、tpinit() へのすべての呼び出しに TPMULTICONTEXTS フラグを含めるか、または tpinit() へのすべての呼び出しにこのフラグを含めません。この規則には、例外が 1 つあります。つまり、tpterm() への呼び出しが正常に終了して、クライアントのすべてのアプリケーション対応付けが終了した場合、次に tpinit() を呼び出すときに必ずしも TPMULTICONTEXTS フラグを含む必要のない状態にプロセスが復元されます。 |
同じプロセス内の各アプリケーションとの対応付けには、別個にセキュリティ検証を行う必要があります。検証の内容は、アプリケーションで使用されているセキュリティ メカニズムのタイプによって異なります。たとえば、Oracle Tuxedo アプリケーションでは、システム レベルのパスワードまたはアプリケーション パスワードを使用します。
マルチコンテキスト アプリケーションのプログラマは、アプリケーションで使用するセキュリティのタイプを決定し、そのセキュリティをプロセス内の各アプリケーションとの対応付けに実装します。
クライアントをアプリケーションから切断する準備ができたら、tpterm() を呼び出します。ただし、マルチコンテキスト アプリケーションでは、tpterm()
を呼び出すと現在のコンテキストが破棄されることに注目してください。その場合、現在のコンテキストで動作しているすべてのスレッドが影響を受けます。アプリケーション プログラマは、tpterm()
が不意に呼び出されることがないように、複数のスレッドを使用する場合は注意してください。
まだ動作中のスレッドがあるコンテキストでは、tpterm() を呼び出さないようにします。そのような状況で tpterm()
を呼び出すと、そのコンテキストと対応付けられていたほかのスレッドが特別な無効コンテキスト状態になります。無効コンテキスト状態では、大部分の ATMI 関数を使用できなくなります。無効コンテキスト状態からスレッドを解放するには、tpsetctxt(3c) または tpterm()
を呼び出します。良く設計されたアプリケーションでは、無効コンテキスト状態が生じることはありません。
注意 : | Oracle Tuxedo システムでは、COBOL アプリケーションのマルチスレッドはサポートされていません。 |
次は、2 つのコンテキストからサービスを呼び出すクライアントで行われる処理の手順をまとめたものです。
TUXCONFIG
環境変数に firstapp
で必要な値を設定します。TPMULTICONTEXTS
フラグを設定して tpinit() を呼び出し、最初のアプリケーションに参加します。tuxputenv()
を呼び出して、TUXCONFIG
環境変数の値を secondapp
コンテキストに必要な値に切り替えます。TPMULTICONTEXTS
フラグを設定して tpinit() を呼び出し、最初のアプリケーションに参加します。firstapp
コンテキストからコンテキストの切り替えを開始します。firstapp
サービスを呼び出します。secondapp
コンテキストに切り替え、secondapp
サービスを呼び出します。firstapp
コンテキストに切り替え、firstapp
サービスを呼び出します。firstapp
コンテキストを終了します。secondapp
コンテキストに切り替え、secondapp
サービスを呼び出します。secondapp
コンテキストを終了します。注意 : | コードを簡単にするために、エラー チェックは省略してあります。 |
#include <stdio.h>
#include "atmi.h" /* Oracle Tuxedo ヘッダ ファイル */
#if defined(__STDC__) || defined(__cplusplus)
main(int argc, char *argv[])
#else
main(argc, argv)
int argc;
char *argv[];
#endif
{
TPINIT * tpinitbuf;
TPCONTEXT_T firstapp_contextID, secondapp_contextID;
/* TUXCONFIG が /home/firstapp/TUXCONFIG に設定されていることを前提とする */
/*
* Oracle Tuxedo システムにマルチコンテキスト モードで接続 */
*/
tpinitbuf=tpalloc(“TPINIT”, NULL, TPINITNEED(0));
tpinitbuf->flags = TPMULTICONTEXTS;
if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}
/*
* 現在のコンテキストへのハンドルを取得
*/
tpgetctxt(&firstapp_contextID, 0);
/*
* tuxputenv を使用して TUXCONFIG の値を変更し、
* 別のアプリケーションに参加 (tpinit)
*/ */
tuxputenv("TUXCONFIG=/home/second_app/TUXCONFIG");
/*
* secondapp に参加 (tpinit)
*/
if (tpinit((TPINIT *) tpinitbuf) == -1) {
(void) fprintf(stderr, "Tpinit failed\n");
exit(1);
}
/*
* secondapp のコンテキストへのハンドルを取得
*/
tpgetctxt(&secondapp_contextID, 0);
/*
* tpgetctxt から取得したハンドルと tpsetctxt を使用して、
* 2 つのコンテキスト間で切り替えが
* できる。firstapp から開始
*/
tpsetctxt(firstapp_contextID, 0);
/*
* firstapp で提供されるサービスを呼び出し、
* 次に secondapp に切り替える
*/
tpsetctxt(secondapp_contextID, 0);
/*
* secondapp で提供されるサービスを呼び出す
* 次に firstapp に戻る
*/
tpsetctxt(firstapp_contextID, 0);
/*
* firstapp で提供されるサービスを呼び出す。操作が終了したら
* firstapp のコンテキストを終了
*/
tpterm();
/*
* secondapp に戻る
*/
tpsetctxt(secondapp_contextID, 0);
/*
* secondapp で提供されるサービスを呼び出す。操作が終了したら
* secondapp のコンテキストを終了し、
* プログラムを終了
*/
tpterm();
return(0);
}
非請求メッセージを処理する各コンテキストでは、非請求メッセージ ハンドラを設定するか、またはプロセス ハンドラのデフォルトが設定されている場合はそれを使用する必要があります。
tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol()
を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol()
を再度呼び出すと、変更できます。
ハンドラの設定は、シングルスレッド アプリケーションまたはシングルコンテキスト アプリケーションのハンドラを設定する場合と同じように行います。詳細については、「tpsetunsol()」を参照してください。
現在処理を行っているコンテキストを識別するには、非請求メッセージ ハンドラ内で tpgetctxt(3c) を使用します。
トランザクションを使用する場合、コーディングで以下の事柄に注意してください。
注意 : | この節で示す手順とサンプル コードは、Oracle Tuxedo システムで提供される C 言語のライブラリ関数を参照します。詳細については、『Oracle Tuxedo C リファレンス』を参照してください。COBOL アプリケーションではマルチコンテキスト サーバの生成に必要なマルチスレッドがサポートされていないので、C 言語の関数に相当する COBOL ルーチンは利用できません。 |
コンテキストを使用する場合、コーディングで以下の事柄に注意してください。
TPNULLCONTEXT
に変更されることはありません。
マルチコンテキスト サーバ使用する場合、コーディングで以下の規則に注意してください。
tpinit()
が呼び出されると、tpinit()
は -1
を返して tperrno(5) に TPEPROTO
を設定します。tpreturn()
を呼び出す前に、そのコンテキストに対応するアプリケーション生成の各スレッドがコンテキストを TPNULLCONTEXT
または別の有効なコンテキストに設定して tpsetctxt(3c) を呼び出す必要があります。
この規則に違反すると、tpreturn() または tpforward() はユーザ ログにメッセージを書き込み、呼び出し側に TPESVCERR
を示して、メイン サーバのディスパッチ ループに制御を戻します。無効 tpreturn()
が実行されたコンテキスト内のスレッドは、無効コンテキスト状態になります。
tpreturn()
または tpforward()
はユーザ ログにメッセージを書き込み、呼び出し側に TPESVCERR
を示して、メイン サーバのディスパッチ ループに制御を戻します。
サーバとサーバ スレッドの初期化と終了には、Oracle Tuxedo システムで提供されるデフォルトの関数を使用できます。
サーバでのサーバ ディスパッチ スレッドのマルチスレッドとマルチコンテキストの動作
オペレーティング システムのスレッド関数を使用して、Tuxedo アプリケーション サーバに新しいスレッドを生成できます。これらの新しいアプリケーションは、Tuxedo システムから独立して動作できます。また、いずれかのサーバ ディスパッチ スレッドと同じコンテキストで動作することもできます。アプリケーション生成のサーバ スレッドは、tpappthrinit(3c)
によって生成された別のコンテキストで動作することもできます。
最初、アプリケーション生成サーバ スレッドは、どの Tuxedo コンテキストにも関連していません。ただし、初期化される前に呼び出された場合、ほとんどの ATMI 関数は暗黙的に tpinit()
を実行します。サーバで tpinit()
を呼び出すことは禁止されているので、そのような呼び出しを行うと問題が発生します。サーバ プロセスで tpinit()
が呼び出されると、tpinit()
は -1
を返して tperrno(5)
に TPEPROTO
を設定します。
そのため、アプリケーション生成のサーバ スレッドは、有効なコンテキストと対応付けを行ってから ATMI 関数を呼び出す必要があります。アプリケーション生成のサーバ スレッドは、次のように動作します。
アプリケーション生成のサーバ スレッドを既存のサーバ ディスパッチ コンテキストに対応付けるには、以下の手順をコーディングします。
注意 : | アプリケーション生成のサーバ スレッドは、tpreturn() または tpforward() (あるいはその両方) を呼び出すことはできません。元のサーバ ディスパッチ スレッドが tpreturn() または tpforward() を呼び出す前に、そのコンテキストにあったすべてのアプリケーション生成のサーバ スレッドは TPNULLCONTEXT または別の有効なコンテキストに切り替える必要があります。 |
注意 : | この規則に違反すると、tpforward() または tpreturn() が失敗し、呼び出し側にサービス エラーが示されます。 |
コード リスト 10-3 は、サービスが別のスレッドを生成して同じサーバ ディスパッチ コンテキストでそのサービスの作業を行うマルチコンテキスト サーバを示しています。このコードは、サーバでアプリケーション スレッドを生成する必要があるアプリケーションで使用します。オペレーティング システムのスレッド関数は、オペレーティング システムによって異なります。このサンプル コードでは、POSIX 関数と ATMI 関数が使用されています。
注意 : | コードを簡単にするために、エラー チェックは省略してあります。また、Oracle Tuxedo システムによってディスパッチされたスレッドだけを使用するマルチコンテキスト サーバも省略してあります。そのようなサーバのコーディングは、スレッド セーフのプログラミング方法が使用されている場合、シングルコンテキスト サーバのコーディングとまったく同じです。 |
#include <pthread.h>
#include <atmi.h>
void *withdrawalthread(void *);
struct sdata {
TPCONTEXT_T ctxt;
TPSVCINFO *svcinfoptr;
};
void
TRANSFER(TPSVCINFO *svcinfo)
{
struct sdata transferdata;
pthread_t withdrawalthreadid;
tpgetctxt(&transferdata.ctxt, 0);
transferdata.svcinfoptr = svcinfo;
pthread_create( &withdrawalthreadid, NULL,
withdrawalthread, &transferdata );
tpcall("DEPOSIT", ...);
pthread_join(withdrawalthreadid, NULL);
tpreturn(TPSUCCESS, ...);
}
void *
withdrawalthread(void *arg)
{
tpsetctxt(arg->ctxt, 0);
tpopen();
tpcall("WITHDRAWAL", ...);
tpclose();
tpsetctxt(TPNULLCONTEXT, 0);
return(NULL);
}
サーバ内のアプリケーション生成のサーバ スレッドは別の Tuxedo コンテキストを生成し、tpappthrinit(3c)
を呼び出してこのコンテキストに自身を対応付けることができます。
tpappthrinit(3c)
によって生成されたコンテキストは、いかなるサーバ ディスパッチ コンテキストーション サーバからも独立しており、アプリケーション サーバが存在するドメインに接続します。tpappthrinit(3c)
によって生成されたコンテキストは、アプリケーション生成のサーバ スレッドがそのコンテキストでの処理を終了した後に、tpappthrterm(3c)
を呼び出して終了する必要があります。tpappthrinit(3c)
を呼び出す際に、ユーザ認証情報をコンテキストと対応付けることができます。アプリケーション生成コンテキストの各アプリケーションとの対応付けには、別個にセキュリティ検証を行う必要があります。tpappthrinit()
/tpappthrterm()
を呼び出すことができるのは、Tuxedo サーバ プロセスのみです。"-t"
オプションを指定してサーバをビルドする必要があります。tpappthrinit()
/tpappthrterm()
を呼び出すことはできません。tpappthrinit()
/tpappthrterm()
を呼び出すことはできません。tpappthrterm()
を呼び出すことはできません。tpappthrterm()
を呼び出さないようにする必要があります。 tpacall()
の呼び出し側かどうかに関係なく、tpgetrply()
を呼び出して以前の tpacall()
呼び出しの応答を受け取ることができます。tpbegin()
を呼び出すことはできません。tpopen()
を呼び出してから、tpbegin()
や SQL 操作などのトランザクション アクティビティを実行する必要があります。トランザクション操作を終了する場合は、tpclose()
を呼び出す必要があります。
コード リスト 10-4 は、サービスが別のスレッドを生成するマルチコンテキスト サーバを示しています。このコードは、サーバでアプリケーション スレッドを生成する必要があるアプリケーションで使用します。このアプリケーション生成のサーバ スレッドは別のコンテキストで動作します。オペレーティング システムのスレッド関数は、オペレーティング システムによって異なります。このサンプル コードでは、POSIX 関数と ATMI 関数が使用されています。
注意 : | コードを簡単にするために、エラー チェックは省略してあります。 |
#include <pthread.h>
#include <atmi.h>
void *withdrawalthread(void *);
void
TRANSFER(TPSVCINFO *svcinfo)
{
pthread_t withdrawalthreadid;
pthread_create( &withdrawalthreadid, NULL,
withdrawalthread, … );
tpcall("DEPOSIT", ...);
pthread_join(withdrawalthreadid, NULL);
tpreturn(TPSUCCESS, ...);
}
void *
withdrawalthread(void *arg)
{
tpappthrinit(NULL);
tpopen();
tpcall("WITHDRAWAL", ...);
tpclose();
tpappthrterm();
return(NULL);
}
サーバのアプリケーション生成スレッドのマルチスレッドとマルチコンテキストの動作
サーバでのサーバ ディスパッチ スレッドのマルチスレッドとマルチコンテキストの動作
注意 : | Oracle Tuxedo システムでは、COBOL アプリケーションのマルチスレッドはサポートされていません。 |
マルチスレッド クライアントを使用する場合、コーディングで以下の規則に注意してください。
tpacall()
呼び出しの応答を受け取ることができます。tpcommit()
はトランザクションをアボートし、-1
を返して tperrno(5) に TPEABORT
を設定します。TUXCONFIG
または WSNADDR
の値を手動で変更してから tpinit() を呼び出します。このような処理が複数のスレッドで行われる場合、環境変数の設定と tpinit()
呼び出しを同期する必要があります。クライアントのすべてのアプリケーション対応付けは、以下の規則に従う必要があります。TPMULTICONTEXTS
フラグを設定して tpinit() 関数を呼び出す必要があります。
クライアントを複数のコンテキストに参加させるには、TPINIT
データ構造体の flags
要素に TPMULTICONTEXTS
フラグを設定して tpinit() 関数を呼び出します。
1 つのプロセスでは、tpinit() へのすべての呼び出しに TPMULTICONTEXTS
フラグを含めます。または、tpinit()
へのすべての呼び出しにこのフラグを含めません。この規則には、例外が 1 つあります。つまり、tpterm() への呼び出しが正常に終了して、クライアントのすべてのアプリケーション対応付けが終了した場合、次に tpinit()
を呼び出すときに必ずしも TPMULTICONTEXTS
フラグを含む必要のない状態にプロセスが復元されます。
TPMULTICONTEXTS
フラグを設定して tpinit() 関数が呼び出されると、アプリケーションとの新しい対応付けが生成され、スレッドに対するカレントの対応付けが指定されます。新しい対応付けが生成される Oracle Tuxedo ドメインは、TUXCONFIG
または WSENVFILE/WSNADDR
環境変数の値で決定されます。
クライアント スレッドが TPMULTICONTEXTS
フラグを設定せずに tpinit() を正常に実行した場合、クライアントのすべてのスレッドがシングルコンテキスト状態 (TPSINGLECONTEXT
) になります。
tpinit() が失敗した場合、呼び出し側スレッドは元のコンテキスト、つまり tpinit()
呼び出しの前に操作していたコンテキスト状態のままになります。
まだ動作中のスレッドがあるコンテキストから tpterm() を呼び出すことはできません。このような状況やそれ以外の状況で tpterm()
を呼び出した結果生じるコンテキスト状態については、「マルチコンテキスト状態の遷移」を参照してください。
マルチコンテキストのアプリケーションでは、いろいろな関数を呼び出すと、呼び出し側スレッド、および呼び出し側プロセスと同じコンテキストでアクティブなその他のスレッドのコンテキスト状態が変化します。次の図は、tpinit()、tpsetctxt(3c)、および tpterm() を呼び出した結果、変化したコンテキスト状態を示しています。tpgetctxt(3c) 関数を呼び出しても、コンテキスト状態は変化しません。
注意 : | tpterm() がマルチコンテキスト状態 (TPMULTICONTEXTS ) で実行しているスレッドによって呼び出されると、呼び出し側スレッドは NULL コンテキスト状態 (TPNULLCONTEXT ) になります。終了するコンテキストに関連するその他すべてのスレッドは、無効コンテキスト状態 (TPINVALIDCONTEXT ) に切り替わります。 |
次の図は、tpinit()、tpsetctxt(3c)、および tpterm() を呼び出した結果、変化したコンテキスト状態を示しています。
tpgetrply() は、tpacall() からの要求に対する応答だけを受け取ります。tpcall() からの要求は、マルチスレッドまたはマルチコンテキストのレベルに関係なく、tpgetrply()
で取得することはできません。
tpgetrply() は、1 つのコンテキスト、つまり tpgetrply() の呼び出し側コンテキストだけで動作します。そのため、TPGETANY
フラグを設定して tpgetrply()
を呼び出すと、同じコンテキストで生成されたハンドルだけが考慮されます。同じように、あるコンテキストで生成されたハンドルを別のコンテキストで使用することはできません。ただし、同じコンテキストで動作するスレッドには、そのハンドルを使用できます。
tpgetrply() をマルチスレッド環境で呼び出す場合、以下の制約があります。
tpgetrply()
を呼び出して同じハンドルの取得を試みると、tpgetrply()
は -1
を返し、tperrno
に TPEPROTO
を設定します。 TPGETANY
フラグを設定して tpgetrply() の応答を待機しているときに、同じコンテキストの別のスレッドが tpgetrply()
を呼び出して特定のハンドルの取得を試みると、tpgetrply() は -1
を返し、tperrno(5) に TPEPROTO
を設定します。
これは、1 つのスレッドが既に tpgetrply() で特定のハンドルを待機しているときに、同じコンテキストの別のスレッドが TPGETANY
フラグを設定して tpgetrply()
を呼び出した場合も同じです。これらの制約により、特定のハンドルを待機しているスレッドがある場合、その応答が別のスレッドに渡されることがなくなります。
TPGETANY
フラグを設定して tpgetrply() の応答を待機できるのは、特定のコンテキスト内で 1 つのスレッドだけです。TPGETANY
フラグを設定して呼び出した tpgetrply()
がまだ処理されていない場合に、同じコンテキストの別のスレッドが同じ呼び出しを行うと、この 2 番目の呼び出しは -1
を返し、tperrno(5) に TPEPROTO
を設定します。
Oracle Tuxedo アプリケーションをマルチコンテキスト マルチスレッド環境で実行する場合、環境変数に関して以下の事柄に注意してください。
注意 : | オペレーティング システム環境が認識されないオペレーティング システムの場合、初期状態では空の環境になっています。 |
TUXCONFIG
、WSNADDR
、または WSENVFILE
環境変数の値を適切な値に変更する必要があります。そのようなアプリケーションがマルチスレッドの場合、以下の処理を確実に行うために、ミューテックスなどのアプリケーション定義の同時実行性制御が必要になります。WSENVFILE
やマシン環境ファイルが読み取られ、そのコンテキストの環境だけが影響を受けます。環境ファイルで上書きされないコンテキスト部分には、プロセス全体に対する以前の環境が適用されます。
以下に示す ATMI 関数は、呼び出し側のアプリケーション コンテキストだけに影響します。
注意 : | tpbroadcast() の場合、ブロードキャスト メッセージは特定のアプリケーションとの対応付けから送られたものとして識別されます。tpnotify(3c) の場合、通知は特定のアプリケーションとの対応付けから送られたものとして識別されます。tpinit() の注記については、「マルチスレッド クライアントでのプロセス単位の関数とデータ構造体」を参照してください。 |
注意 : | tpsetunsol() がコンテキストに対応付けされていないスレッドから呼び出されると、新しく生成されるすべての tpinit() コンテキストに対して、プロセス単位のデフォルトの非請求メッセージ ハンドラが作成されます。特定のコンテキストは、コンテキストがアクティブのときに tpsetunsol() を再度呼び出して、そのコンテキストの非請求メッセージ ハンドラを変更することができます。プロセス単位のデフォルトの非請求メッセージ ハンドラは、コンテキストに現在対応付けされていないスレッドで tpsetunsol() を再度呼び出すと、変更できます。 |
以下に示す Oracle Tuxedo 関数は、呼び出し側のプロセス全体に影響します。
TPMULTICONTEXTS
モードまたはシングルコンテキスト モードに応じて適用されます。「マルチスレッド クライアントでのコンテキスト単位の関数とデータ構造体」も参照してください。
シングルコンテキスト モード、マルチコンテキスト モード、または非初期化モードのどれを使用するかは、プロセス全体に影響します。また、バッファ タイプ スイッチ、ビュー キャッシュ、および環境変数の値も、プロセス単位の関数です。
Ferror、Ferror32(5)、tperrno(5)、tpurcode(5)、および Uunix_err
変数は、各スレッドに固有です。
次のサンプル コードは、ATMI 呼び出しを使用するマルチスレッド クライアントを示しています。スレッド関数は、オペレーティング システムによって異なります。この例では、POSIX 関数が使用されています。
注意 : | コードを簡単にするために、エラー チェックは省略してあります。 |
#include <stdio.h>
#include <pthread.h>
#include <atmi.h>
TPINIT * tpinitbuf;
int timeout=60;
pthread_t withdrawalthreadid, stockthreadid;
TPCONTEXT_T ctxt;
void * stackthread(void *);
void * withdrawalthread(void *);
main()
{
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
/*
* このコードでは、withdrawal スレッドと deposit スレッドという別のスレッドを
* 使用して振り込みを行う。また、Oracle 株の現在の価格を
* 別のアプリケーションから取得し、送金した金額で
* 購入できる株数を計算する
*/
tpinitbuf->flags = TPMULTICONTEXTS;
/* 残りの tpinitbuf を設定 */
tpinit(tpinitbuf);
tpgetctxt(&ctxt, 0);
tpbegin(timeout, 0);
pthread_create(&withdrawalthreadid, NULL, withdrawalthread, NULL);
tpcall("DEPOSIT", ...);
/* withdrawal スレッドの完了を待機 */
pthread_join(withdrawalthreadid, NULL);
tpcommit(0);
tpterm();
/* stock スレッドの完了を待機 */
pthread_join(stockthreadid, NULL);
/* 結果を出力 */
printf("$%9.2f has been transferred \
from your savings account to your checking account.\n", ...);
printf("At the current Oracle stock price of $%8.3f, \
you could purchase %d shares.\n", ...);
exit(0);
}
void *
stockthread(void *arg)
{
/* ほかのスレッドが tpinit() を呼び出しているので、
* TUXCONFIG を再設定してもスレッドに影響しない
*/
tuxputenv("TUXCONFIG=/home/users/xyz/stockconf");
tpinitbuf->flags = TPMULTICONTEXTS;
/* 残りの tpinitbuf を設定 */
tpinit(tpinitbuf);
tpcall("GETSTOCKPRICE", ...);
/* main() でもアクセスできる変数に株価を格納 */
tpterm();
return(NULL);
}
void *
withdrawalthread(void *arg)
{
/* 別のアプリケーションから株価を取得するために新しいスレッドを
* 生成
*/
pthread_create(&stockthreadid, NULL, stockthread, NULL);
tpsetctxt(ctxt, 0);
tpcall("WITHDRAWAL", ...);
return(NULL);
}
ほとんどの場合、マルチスレッド サーバはマルチコンテキストでもあります。マルチスレッド サーバのコーディングについては、「サーバでサーバ ディスパッチのマルチコンテキストおよびマルチスレッドのスレッドを使用するためのコーディング」を参照してください。
buildserver(1) や buildclient(1) など、コンパイルまたはビルドの実行可能ファイル用に Oracle Tuxedo システムで提供されるプログラムには、必要なコンパイラ フラグが自動的に設定されます。これらのツールを使用すると、コンパイル時にフラグを設定する必要がありません。
ただし、最終的なコンパイルの前に .c
ファイルを .o
ファイルにコンパイルする場合は、プラットフォーム固有のコンパイラ フラグを設定する必要があります。そのようなフラグは、単一のプロセスにリンクするすべてのコードに一貫して設定しなければなりません。
マルチスレッド サーバを生成する場合、-t
オプションを指定して buildserver(1) コマンドを実行する必要があります。これはマルチスレッド サーバの場合に必須のオプションです。ビルド時にこのオプションが指定されておらず、その後、MAXDISPATCHTHREADS
の値が 1 を超えるコンフィグレーション ファイルを使用して新しいサーバを起動すると、警告メッセージがユーザ ログに記録され、サーバはシングルスレッドの動作に戻ります。
マルチスレッド環境で .c
ファイルを .o
ファイルにコンパイルする場合に必要なオペレーティング システム固有のコンパイラ パラメータを識別するには、-v
オプションを指定して buildclient(1) または buildserver(1) をテスト ファイルで実行します。
マルチスレッドやマルチコンテキストのコードをテストする場合、以下を行うことをお勧めします。
エラーの原因を調べる場合、まず TPMULTICONTEXTS
フラグが設定されているかどうか、またその設定内容を確認します。このフラグが設定されていないこと、または正しく設定されていないことが原因でよくエラーが起こります。
TPMULTICONTEXTS
フラグを使用できない場合にこのフラグがプロセスに設定されているとき、または TPMULTICONTEXTS
を設定する必要がある場合に設定されていないとき、tpinit() は -1
を返し、tperrno
に TPEPROTO
を設定します。
TPMULTICONTEXTS
が設定されていない場合に tpinit() が呼び出されると、この関数はシングルコンテキスト アプリケーションで呼び出されたときと同じように動作します。tpinit()
が既に 1 回呼び出されている場合、それ以降の tpinit()
呼び出しで TPMULTICONTEXTS
フラグが設定されていなくても、この関数は正常に終了します。これは、アプリケーション内の TUXCONFIG
または WSNADDR
環境変数の値が変更されている場合にも当てはまります。TPMULTICONTEXTS
フラグを設定せずに tpinit()
を呼び出すことは、マルチコンテキスト モードではできません。
クライアントがアプリケーションに参加していない場合に、tpinit() を呼び出す別の関数の呼び出しの結果として、暗黙的に tpinit()
が呼び出されると、Oracle Tuxedo システムでは TPMULTICONTEXTS
フラグが設定されずに tpinit()
が呼び出されたと解釈されます。これは、以降の tpinit()
呼び出しでどのフラグが使用されるかを判断するためです。
ほとんどの ATMI 関数は、既にマルチコンテキスト モードで動作しているプロセスのコンテキストに対応付けされていないスレッドに呼び出された場合、tperrno(5)=TPEPROTO
が設定されて失敗します。
一部のオペレーティング システムでは、オペレーティング システムのデフォルトのスレッド スタック サイズが Oracle Tuxedo システムで使用するには十分ではありません。Compaq Tru64 UNIX と UnixWare の 2 つのオペレーティング システムは、サイズが小さいことが認識されています。デフォルトのスレッド スタック サイズのパラメータが使用されている場合に、スタックを多用する関数がメイン スレッド以外のスレッドで呼び出されると、これらのプラットフォーム上のアプリケーションはコア ダンプします。通常、生成されるコア ファイルから、スタック サイズの不足が問題の原因であることはわかりません。
サーバ ディスパッチ スレッドやクライアントの非請求メッセージ スレッドなど、Oracle Tuxedo システムで独自のスレッドが生成される場合、これらのプラットフォームのデフォルトのスタック サイズのパラメータを適切な値に調整できます。ただし、アプリケーションで独自のスレッドが生成される場合、アプリケーションで十分なスタック サイズを指定する必要があります。Oracle Tuxedo システムにアクセスするスレッドには、最低 128 K を指定してください。
Compaq Tru64 UNIX および POSIX スレッドが使用されるそのほかのシステムでは、スレッドのスタック サイズは、pthread_create()
を呼び出す前に pthread_attr_setstacksize()
を呼び出して指定します。UnixWare では、スレッドのスタック サイズは thr_create()
の引数として指定されます。この問題の詳細については、お使いのオペレーティング システムのマニュアルを参照してください。
エラーはユーザ ログに記録されます。シングルコンテキスト モードでもマルチコンテキスト モードでも、各エラーに対して次の情報が記録されます。
process_ID.thread_ID.context_ID