DB2 CLI は次のプラットフォーム上でスレッドの並行実行をサポートしています。
スレッドをサポートするその他のプラットフォームでは、 DB2 CLI は DB2 CLI に対するすべての呼び出しをシリアル化することでスレッドの安全を保証しています。言い換えれば、DB2 CLI は常に再入可能ということです。
注: | アプリケーションを作成していて、 DB2 CLI 呼び出しおよび組み込み SQL または DB2 API 呼び出しを使用する場合には、 マルチスレッド混合アプリケーションを参照してください。 |
並行実行とは、 2 つのスレッドが (同時に実行可能なマルチプロセッサー上で) それぞれ独立して実行できることを表しています。たとえば、アプリケーションはデータベース間のコピーを次の方法で実現することができます。
対照的に、DB2 CLI がすべての関数呼び出しをシリアル化する場合は、一度に 1 つのスレッドだけが DB2 CLI 関数を実行することができます。その他のスレッドすべては現行スレッドの処理が終わるまで待ってからでなければ、実行の機会を獲得することはできません。
DB2 CLI アプリケーション内にもう一つのスレッドを作成する一般的な理由の多くは、実行しているスレッド以外のスレッドを使用すると、(たとえば、長時間の照会の実行を避けて) SQLCancel() を呼び出せるようにすることができます。
注: | 複数スレッドをサポートしているプラットフォームでは、非同期の SQL モデル (これは Windows 3.1 のようなスレッドのないオペレーティング・システム (OS) 用に設計されている) を使うよりも、上記の方式を使用すべきです。ご使用になるアプリケーションでマルチ・スレッドを使用できない場合、 CLI の非同期実行を参照してください。 |
たいていの GUI ベースのアプリケーションではスレッドを使用して、ユーザーとの対話が優先度の高いスレッドで扱われるようにしています。それに比べると、他のアプリケーション・タスクは優先度が低くなっています。アプリケーションでは、 1 つのスレッドだけですべての DB2 CLI 関数 (SQLCancel() は例外です) を実行できるようにしています。この場合、スレッド関連のアプリケーション設計上の問題はありません。それは、 DB2 CLI との対話に使用するデータ・バッファーを 1 つのスレッドだけがアクセスできるようにしているからです。
複数の接続を使用し、幾らかの時間がかかるステートメントを実行しているアプリケーションでは、スループットを改善するために、マルチ・スレッドでDB2 CLI 関数を実行することを考慮してください。そのようなアプリケーションは、マルチスレッドのアプリケーション、特にデータ・バッファーの共用が関係するマルチスレッド・アプリケーションを作成する際の標準的な慣習に従ってください。以下のセクションでは、複雑なマルチスレッド・アプリケーションを作成するために、 DB2 CLI が保証することと、アプリケーションが保証する必要のあることについて、詳細を説明します。
DB2 CLI で割り振られる資源は、スレッドの安全が保証されています。これは、共用グローバルまたは接続特有のセマフォーのいずれかを使用して成し遂げられます。同時に 1 つのスレッドだけが、環境ハンドルを入力として受け入れる DB2 CLI 関数を実行することが可能です。接続ハンドル (つまりその接続ハンドル上で割り振られるステートメントまたは記述子) を受け入れるその他の関数すべては、接続ハンドル上でシリアル化されます。
このことは、スレッドが接続ハンドル (または接続ハンドルの子) を指定して関数の実行を一度開始すると、他のスレッドはブロックされ、実行中のスレッドが返されるまで待機することを意味しています。これに対する 1 つの例外は SQLCancel() で、別のスレッドで現在実行しているステートメントを取り消すことができます。この理由のために、最も無理のない設計とは、接続ごとに 1 つのスレッドを対応付け、 SQLCancel() 要求を処理するためにさらに 1 つのスレッドを加えることです。こうすれば、各スレッドは他のスレッドから独立して実行可能です。
一例として、スレッドが、あるスレッド内の 1 つのハンドルを使用していて、それから別のスレッドが関数呼び出しの間にそのハンドルを解放した場合、そのハンドルを使用する次の試みには結果として SQL_INVALID_HANDLE の戻りコードが生じることになります。
注: | これは DB2 CLI アプリケーションにのみ適用されます。この場合のハンドルはポインターであり、別のスレッドがそのハンドルを解放していれば、そのポインターがもはや有効ではないので、ODBC アプリケーションはトラップします。この理由のために、下記のモデルに従うのが最善です。 |
注: | マルチスレッド・アプリケーションには、プラットフォームやコンパイラーに固有のリンク・オプションが必要になることがあります。詳細な説明については、アプリケーション構築の手引き を参照してください。 |
次に 1 つの例を示します。
このモデルを使用すると、非 SQL 関連のタスクを実行するのに複数のスレッドが使用される場合には、マスター・スレッドは接続よりも多くのスレッドを持つことができ、アプリケーションが種々のデータベースに対するアクティブ接続のプールを維持し、しかもアクティブ・タスクの数を制限したい場合には、マスター・スレッドはスレッドよりも多くの接続を持つことができます。
さらに重要なことに、これにより 2 つのスレッドが同時に同一の接続またはステートメント・ハンドルを使用しようとすることがなくなります。 DB2 CLI はその資源へのアクセスを制御しますが、結合列やパラメーター・バッファーのようなアプリケーション資源は DB2 CLI により制御されません。したがってアプリケーションは、バッファーへのポインターが同時に 2 つのスレッドで使用されないように保証する必要があります。すべての据え置き引き数は、列またはパラメーターがアンバインドされるまで有効に保つ必要があります。
2 つのスレッドがデータ・バッファーを共用することが必要な場合、アプリケーションは何らかの形の同期メカニズムを実装する必要があります。たとえば、上記に言及されているデータベース間のコピー・シナリオにおいて、共用バッファーの使用はアプリケーションによって同期をとる必要があります。
アプリケーションは、データベースおよびアプリケーションにある共用資源でデッドロック状態が発生する可能性を考慮に入れておく必要があります。
DB2 はサーバーでデッドロックを検出すると、 1 つまたは複数のトランザクションをロールバックしてデッドロックを解消することができます。それでも、次のような場合、アプリケーションにはデッドロックの可能性があります。
上記の場合には、DB2 サーバーはデッドロックではなく、ロックだけを探そうとします。それで、データベース LOCKTIMEOUT 構成の設定が変更されない限り、アプリケーションはいつまでも待ち続けることになります。
上記に提案されているモデルは、この問題を避け、スレッドが接続における実行を一度開始すると、スレッド間でアプリケーション資源を共有することはありません。
既存のマルチスレッドの DB2 CLI アプリケーションが、シリアル化されたバージョン (バージョン 5 より前) の DB2 CLI を使用して正常に実行したにもかかわらず、バージョン 5 またはそれ以降の DB2 CLI を使用して実行するときに同期の問題を被ることがあります。
この場合には、 DISABLEMULTITHREAD の CLI/ODBC 構成キーワードを、 1 にセットしてください。それによって、DB2 CLI はすべての関数呼び出しをシリアル化することができます。これが必要な場合には、アプリケーションを分析の上、訂正してください。
マルチスレッド・アプリケーションで、 CLI 呼び出しを DB2 API 呼び出しや組み込み SQL と混合することができます。アプリケーションの編成を最善のものにするには、どのタイプの呼び出しを最初に行うかを考慮する必要があります。
最初に DB2 CLI 呼び出しを実行する場合
DB2 CLI ドライバーは自動的に DB2 のコンテキスト API を呼び出し、アプリケーション用のコンテキストを割り当てて管理します。このことは、他の DB2 API または組み込み SQL を呼び出す前に SQLAllocEnv() を呼び出すすべてのアプリケーションが、 SQL_CTX_MULTI_MANUAL に設定されるコンテキスト・タイプで初期設定されることを示します。
この場合には、アプリケーションで DB2 CLI を使用して、すべてのコンテキストを割り当てて管理する必要があります。 DB2 CLI を使用して、すべての接続ハンドルを割り振り、すべての接続を実行します。組み込み SQL を呼び出す前に、各スレッドで SQLSetConnect() 関数を呼び出してください。 DB2 CLI 関数が同一スレッドに呼び出された後に、DB2 API は呼び出し可能となります。
最初に DB2 API 呼び出しか組み込み SQL を実行する場合
アプリケーションが CLI 関数の前に DB2 API または組み込み SQL を呼び出す場合は、 DB2 CLI ドライバーは DB2 のコンテキスト API を自動的に呼び出しません。
DB2 API または組み込み SQL を呼び出すすべてのスレッドはコンテキストに結び付いている必要があります。そうでないと、その呼び出しは SQL1445N の SQLCODE により失敗します。スレッドをコンテキストに明示的に結び付ける DB2 API sqleAttachToCtx()、または DB2 CLI 関数 (たとえば、SQLSetConnection()) を呼び出すことでこのことを行えます。
この場合には、アプリケーションがすべてのコンテキストを明示的に管理しなければなりません。
コンテキスト API を用いて、DB2 CLI 関数を呼び出す前にコンテキストを割り当て接続します。 (SQLAllocEnv() は、既存のコンテキストを省略時のコンテキストとして使用します)。 SQL_ATTR_CONN_CONTEXT の接続属性を使用して、それぞれの DB2 CLI 接続が用いるコンテキストを明示的に設定します。
既存の混合アプリケーションの実行に関する詳細は、付録 B, アプリケーションの移行を参照してください。