Pro*C/C++プリコンパイラは、次に示すユーザー・インタフェース機能によってマルチスレッド・アプリケーションをサポートしています。
コマンドライン・オプションTHREADS=YES|NO
埋込みSQL文とディレクティブ
スレッド・セーフなSQLLIBパブリック関数
THREADS=YESをコマンドラインに指定すると、ガイドラインに従っている場合、生成されたコードがスレッド・セーフであることがPro*C/C++プリコンパイラにより保証されます。THREADS=YESと指定すると、Pro*C/C++ではすべてのSQL文がユーザー定義のランタイム・コンテキスト範囲内で実行されることが検証されます。プログラムがこの要件を満たしていないと、プリコンパイラ・エラーが戻されます。
関連項目:
THREADSオプションのガイドラインは、プログラミングの考慮事項を参照してください。
ランタイム・コンテキストおよびスレッドの定義と使用に対応した埋込みSQLおよびディレクティブは、次のとおりです。
EXEC SQL ENABLE THREADS;
EXEC SQL CONTEXT ALLOCATE :context_var;
EXEC SQL CONTEXT USE { :context_var | DEFAULT};
EXEC SQL CONTEXT FREE :context_var;
これらのEXEC SQL文では、context_varがランタイム・コンテキストへのハンドルで、次のようにsql_context型として宣言する必要があります。
sql_context <context_variable>;
DEFAULTを使用すると、別のCONTEXT USE文でオーバーライドされるまで、以降のすべての埋込みSQL文にデフォルト(グローバル)ランタイム・コンテキストが使用されます。
この実行SQL文は、複数のスレッドをサポートするプロセスを初期化します。このSQL文は、マルチスレッド・アプリケーション内の最初の実行SQL文にしてください。
注意:
Pro*C/C++プリコンパイラとXAを併用する場合は、XAのマルチスレッドを使用する必要があります。EXEC SQL ENABLE THREADS文を使用してPro*Cのマルチスレッドを使用するとエラーになります。
この実行SQL文は指定されたランタイム・コンテキストにメモリーを割り当てて初期化します。ランタイム・コンテキスト変数はsql_context型として宣言する必要があります。
このディレクティブはプリコンパイラに、後続の実行SQL文に対して指定したランタイム・コンテキストを使用するように指示します。ランタイム・コンテキストを指定するには、EXEC SQL CONTEXT ALLOCATE文で事前に割り当てる必要があります。
EXEC SQL CONTEXT USEディレクティブは、EXEC SQL WHENEVERディレクティブと同様に、指定したソース・ファイル内でこのディレクティブの後に続くすべての実行SQL文に影響し、C言語の標準のスコープ規則には従いません。次の例では、function2()のUPDATE文はグローバル・ランタイム・コンテキストctx1を使用しています。
sql_context ctx1; /* declare global context ctx1 */
function1()
{
sql_context :ctx1; /* declare local context ctx1 */
EXEC SQL CONTEXT ALLOCATE :ctx1;
EXEC SQL CONTEXT USE :ctx1;
EXEC SQL INSERT INTO ... /* local ctx1 used for this stmt */
...
}
function2()
{
EXEC SQL UPDATE ... /* global ctx1 used for this stmt */
}
ローカル・コンテキストを使用した後でグローバル・コンテキストを使用するには、次のコードをfunction1()に追加します。
function1()
{
sql_context :ctx1; /* declare local context ctx1 */
EXEC SQL CONTEXT ALLOCATE :ctx1;
EXEC SQL CONTEXT USE :ctx1;
EXEC SQL INSERT INTO ... /* local ctx1 used for this stmt */
EXEC SQL CONTEXT USE DEFAULT;
EXEC SQL INSERT INTO ... /* global ctx1 used for this stmt */
...
}
次の例に、グローバル・ランタイム・コンテキストはありません。プリコンパイラでは、UPDATE文に対して生成されたコードでctx1ランタイム・コンテキストが参照されます。ただし、function2()のスコープにコンテキスト変数がないため、コンパイル時にエラーが発生します。
function1()
{
sql_context ctx1; /* local context variable declared */
EXEC SQL CONTEXT ALLOCATE :ctx1;
EXEC SQL CONTEXT USE :ctx1;
EXEC SQL INSERT INTO ... /* ctx1 used for this statement */
...
}
function2()
{
EXEC SQL UPDATE ... /* Error! No context variable in scope */
}
次に示すコード例では、2つの典型的なプログラミング・モデルに埋込みSQL文とプリコンパイラ・ディレクティブを使用する方法を示しています。thread_create()を使用してスレッドを作成します。
最初の例では、複数のスレッドが複数のランタイム・コンテキストを使用する場合を示します。
main()
{
sql_context ctx1,ctx2; /* declare runtime contexts */
EXEC SQL ENABLE THREADS;
EXEC SQL CONTEXT ALLOCATE :ctx1;
EXEC SQL CONTEXT ALLOCATE :ctx2;
...
/* spawn thread, execute function1 (in the thread) passing ctx1 */
thread_create(..., function1, ctx1);
/* spawn thread, execute function2 (in the thread) passing ctx2 */
thread_create(..., function2, ctx2);
...
EXEC SQL CONTEXT FREE :ctx1;
EXEC SQL CONTEXT FREE :ctx2;
...
}
void function1(sql_context ctx)
{
EXEC SQL CONTEXT USE :ctx;
/* execute executable SQL statements on runtime context ctx1!!! */
...
}
void function2(sql_context ctx)
{
EXEC SQL CONTEXT USE :ctx;
/* execute executable SQL statements on runtime context ctx2!!! */
...
}
次の例では、共通のランタイム・コンテキストを共有する複数のスレッドを使用する方法を示します。function1()およびfunction2()で実行されるSQL文は同時に実行される可能性があるため、すべての実行EXEC SQL文をmutexで囲むことで、データ操作を逐次的、つまり安全に行うことが必要です。
main()
{
sql_context ctx; /* declare runtime context */
EXEC SQL CONTEXT ALLOCATE :ctx;
...
/* spawn thread, execute function1 (in the thread) passing ctx */
thread_create(..., function1, ctx);
/* spawn thread, execute function2 (in the thread) passing ctx */
thread_create(..., function2, ctx);
...
}
void function1(sql_context ctx)
{
EXEC SQL CONTEXT USE :ctx;
/* Execute SQL statements on runtime context ctx. */
...
}
void function2(sql_context ctx)
{
EXEC SQL CONTEXT USE :ctx;
/* Execute SQL statements on runtime context ctx. */
...
}
OracleはSQLLIBコードがスレッド・セーフであることを保証しますが、Pro*C/C++のソース・コードがスレッドで正しく動作するように設計する必要があります。たとえば、静的変数とグローバル変数は慎重に使用してください。
また、マルチスレッド・アプリケーションの設計時には次の点に注意してください。
SQLCAをスレッド・セーフな構造体として宣言します。通常は自動変数として、ランタイム・コンテキストごとに1つずつ宣言します。
SQLDAをスレッド・セーフな構造体として宣言します(SQLCAと同様)。通常は、自動変数としてランタイム・コンテキストごとに1つずつ宣言します。
スレッド・セーフ方式でホスト変数を宣言するときは、静的ホスト変数およびグローバル・ホスト変数の使用に注意してください。
複数のスレッドでランタイム・コンテキストを同時に使用するのを避けます。
デフォルトのデータベース接続を使用するか、あるいはAT句を使用して明示的に定義するかを判断します。
さらに、複数の埋込みSQLの実行文(EXEC SQL UPDATEなど)をランタイム・コンテキストで同時に未解決にしないでください。
プリコンパイル済アプリケーションの既存の要件も適用されます。たとえば、特定のカーソルへの参照はすべて同じソース・ファイルに含まれている必要があります。