ページの先頭行へ戻る
Symfoware Server V10.0.0/V10.0.1 アプリケーション開発ガイド(埋込みSQL編)

A.10 マルチスレッド環境で動作するアプリケーションの例

マルチスレッド環境で動作するアプリケーションの例を以下に示します。

スレッドを2つ起動し、並列で動作する例です。

Windows以下の例に示したアプリケーションを動作させるためには、コンパイル・リンク時のコマンドのオプションに-DNTを指定してください。

Linux以下の例に示したアプリケーションを動作させるためには、コンパイル・リンク時のコマンドのオプションに-DLinuxを指定してください。

#if defined(NT)
#include <windows.h>
#else
#if defined(Linux)
#include <stdio.h>
#include <pthread.h>
#else
#include <stdio.h>
#include <thread.h>
#endif
#endif
#include "sqlrdbei.h"

#define SQL_STATEMENT1   \
 "SELECT WISTRU1 FROM SI_SCHM1.SI_TABLE WHERE WIUNQU1=1"                     …… (1)

void* sub_threadA(void *);                                                   …… (2)
void* sub_threadB(void *);

int main(void)
{
    SQLRETURN   ret    =0;
    SQLHDBS     ses_id =0;
    SQLHDBS     ses_id2=0;

#if defined(NT)
    unsigned long t_threadA;
    unsigned long t_threadB;
    HANDLE thread_tbl[2];
#else
#if defined(Linux)
    pthread_t t_threadA;
    pthread_t t_threadB;
#else
    thread_t t_threadA;
    thread_t t_threadB;
    thread_t ret_threadA;
    thread_t ret_threadB;
#endif
#endif

    ret = SQLThrAllocID( &ses_id );                                           …… (3)
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrAllocID(code) = %d\n" , ret );
        return 1;
    }
    ret = SQLThrAllocID( &ses_id2 );
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrAllocID(code) = %d\n" , ret );
        ret = SQLThrFreeID( ses_id );
        return 1;
    }

#if defined(NT)
    t_threadA = (unsigned long)_beginthread( sub_threadA, 0, &ses_id);         …… (4)
    thread_tbl[0] = (HANDLE)t_threadA;
    t_threadB = (unsigned long)_beginthread( sub_threadB, 0, &ses_id2);
    thread_tbl[1] = (HANDLE)t_threadB;
    WaitForMultipleObjects( 1, thread_tbl, TRUE, INFINITE );                   …… (5)
#else
#if defined(Linux)
    pthread_create(&t_threadA, NULL, sub_threadA, (void *)&ses_id );         …… (4)
    pthread_create(&t_threadB, NULL, sub_threadB, (void *)&ses_id2);
    pthread_join(t_threadA, NULL);                                           …… (5)
    pthread_join(t_threadB, NULL);
#else
    thr_create(NULL, 0, sub_threadA, (void *)&ses_id,  THR_BOUND, &t_threadA); …… (4)
    thr_create(NULL, 0, sub_threadB, (void *)&ses_id2, THR_BOUND, &t_threadB);
    thr_join(t_threadA, &ret_threadA, NULL);                                 …… (5)
    thr_join(t_threadB, &ret_threadB, NULL);
#endif
#endif

    ret = SQLThrFreeID( ses_id );                                             …… (6)
    ret = SQLThrFreeID( ses_id2 );

    return 0;

}

(1) 実行するSQL文を定義します。

(2) スレッド(サブプロセス)の関数を宣言します。

(3) セションを作成します。セションを作成する関数を実行することによって、セションIDを受け取ります。

(4) スレッドを作成して、sub_threadAおよびsub_threadBを実行します。

(5) sub_threadAおよびsub_threadBの両方の処理が終了してからセションを破棄するように制御します。

(6) セションを破棄します。

void* sub_threadA(void *ses_id_p)
{
EXEC SQL BEGIN DECLARE SECTION;
    char    SQLSTATE[6];                                     …… (1)
    char    SQLMSG[256];
    VARCHAR statement[256];
    char    dataA[53];
EXEC SQL END   DECLARE SECTION;

    SQLHDBS     ses_id = *(SQLHDBS *)ses_id_p;
    SQLRETURN   ret=0;

    memset(SQLSTATE, 0x00, 6);
    memset(SQLMSG,   0x00, 256);
    memset(dataA,    0x00, 53);

    ret = SQLThrStartID( ses_id );                             …… (2)
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrStartID(code) = %d\n" , ret );
        return 0;
    }

    EXEC SQL DECLARE CU1 CURSOR FOR CMD1;                       …… (3)

    EXEC SQL WHENEVER SQLERROR GO TO :CONNECT_ERROR;

    EXEC SQL CONNECT TO DEFAULT;                               …… (4)
    printf( "CONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "CONNECT(SQLMSG)   = %s\n" , SQLMSG );

    EXEC SQL WHENEVER SQLERROR CONTINUE;

    strcpy( statement.sqlvar, SQL_STATEMENT1 );
    statement.sqllen = strlen( statement.sqlvar );
    EXEC SQL PREPARE CMD1 FROM :statement;
    printf( "PREPARE(SQLSTATE):%s\n", SQLSTATE );
    printf( "PREPARE(SQLMSG):%s\n", SQLMSG );

    EXEC SQL OPEN CU1 ;                                        …… (5)
    printf( "OPEN(SQLSTATE):%s\n", SQLSTATE );
    printf( "OPEN(SQLMSG):%s\n", SQLMSG );

    while ( strcmp(SQLSTATE,"00000")==0 ) {
        EXEC SQL FETCH CU1 INTO :dataA ;                        …… (6)
        printf( "FETCH(DATA):%s\n", dataA );
        printf( "FETCH(SQLSTATE):%s\n", SQLSTATE );
        printf( "FETCH(SQLMSG):%s\n", SQLMSG );
    }

    EXEC SQL CLOSE CU1;                                        …… (7)
    printf( "CLOSE(SQLSTATE):%s\n", SQLSTATE );
    printf( "CLOSE(SQLMSG):%s\n", SQLMSG );

    EXEC SQL DEALLOCATE PREPARE CMD1;
    printf( "DEALLO_PREP(SQLSTATE):%s\n", SQLSTATE );
    printf( "DEALLO_PREP(SQLMSG):%s\n", SQLMSG );

    EXEC SQL COMMIT WORK;                                      …… (8)
    printf( "COMMIT(SQLSTATE) = %s\n" , SQLSTATE ) ;
    printf( "COMMIT(SQLMSG)   = %s\n" , SQLMSG );

    EXEC SQL DISCONNECT ALL;                                   …… (9)
    printf( "DISCONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "DISCONNECT(SQLMSG)   = %s\n" , SQLMSG );

    ret = SQLThrEndID( ses_id );                              …… (10)
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrEndID(code) = %d\n" , ret );
        return 0;
    }

    return 0;

CONNECT_ERROR:                                              …… (11)
    printf( "CONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "CONNECT(SQLMSG)   = %s\n" , SQLMSG );
    ret = SQLThrEndID ( ses_id );
    return 0;

}

(1) SQLSTATEとSQLMSGを各スレッドで宣言します。

(2) セションを開始します。セションを開始する関数を実行することにより、セションとスレッド(sub_threadA)が対応付けられます。

(3) カーソルを宣言します。

(4) サーバとコネクションを接続します。

(5) カーソルをオープンします。

(6) カーソルを位置づけ、その行を読み込みます。

(7) カーソルをクローズします。

(8) トランザクションをCOMMIT文により終了します。

(9) サーバとのコネクションを切断します。

(10) セションを終了します。

(11) サーバとのコネクションに失敗した場合は、セションを終了します。

void* sub_threadB(void *ses_id_p)
{
EXEC SQL BEGIN DECLARE SECTION;
    char    SQLSTATE[6];                                    …… (1)
    char    SQLMSG[256];
EXEC SQL END   DECLARE SECTION;

    SQLHDBS     ses_id = *(SQLHDBS *)ses_id_p;
    SQLRETURN   ret=0;

    memset(SQLSTATE, 0x00, 6);
    memset(SQLMSG,   0x00, 256);

    ret = SQLThrStartID( ses_id );                          …… (2)
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrStartID(code) = %d\n" , ret );
        return 0;
    }

    EXEC SQL WHENEVER SQLERROR GO TO :CONNECT_ERROR;

    EXEC SQL CONNECT TO 'SI_DB333';                          …… (3)
    printf( "CONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "CONNECT(SQLMSG)   = %s\n" , SQLMSG );

    EXEC SQL WHENEVER SQLERROR CONTINUE;

    EXEC SQL INSERT INTO SI_SCHM1.SI_TABLE2
             VALUES(1,1,1,1,1,1,1,1,1,1,'R','DD','BBBB');    …… (4)
    printf( "INSERT(SQLSTATE):%s\n", SQLSTATE );
    printf( "INSERT(SQLMSG):%s\n", SQLMSG );

    EXEC SQL COMMIT WORK;                                    …… (5)
    printf( "COMMIT(SQLSTATE) = %s\n" , SQLSTATE ) ;
    printf( "COMMIT(SQLMSG)   = %s\n" , SQLMSG );

    EXEC SQL DISCONNECT ALL;                                 …… (6)
    printf( "DISCONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "DISCONNECT(SQLMSG)   = %s\n" , SQLMSG );

    ret = SQLThrEndID( ses_id );                             …… (7)
    if ( ret != SQLRDB_NORMAL ) {
        printf( "SQLThrEndID(code) = %d\n" , ret );
        return 0;
    }

    return 0;

CONNECT_ERROR:                                               …… (8)
    printf( "CONNECT(SQLSTATE) = %s\n" , SQLSTATE );
    printf( "CONNECT(SQLMSG)   = %s\n" , SQLMSG );
    ret = SQLThrEndID( ses_id );
    return 0;

}

(1) SQLSTATEとSQLMSGを各スレッドで宣言します。

(2) セションを開始します。セションを開始する関数を実行することにより、セションとスレッド(sub_threadB)が対応付けられます。

(3) サーバとコネクションを接続します。

(4) INSERT文を実行して値を挿入します。

(5) トランザクションをCOMMIT文により終了します。

(6) サーバとのコネクションを切断します。

(7) セションを終了します。

(8) サーバとのコネクションに失敗した場合は、セションを終了します。

マルチスレッド環境で動作するアプリケーションを作成する場合の注意事項

アプリケーションを作成するには、ホスト変数および複数スレッド間の排他などを考慮して、実行したSQL文によるデータベースの検索および更新結果が正しくなるようにしなければなりません。以下に注意点を示します。

状態変数およびメッセージ変数の宣言については、“2.6 名前の一意性と有効範囲”を参照してください。