/* mytt.c * スレッドテーブルのサンプル * ・保持するスレッド数の上限を設定。 */ #include "apr_general.h" #include "apr_errno.h" #include "apr_thread_proc.h" #include "mytt.h" /* * スレッドテーブル * ・スレッドテーブルは処理中のサブスレッドのスレッドハンドルを保持する配列。 * ・インデクス変数で次の位置をポイントする。 * 条件: * ・スレッドテーブルはメインスレッドでのみ操作する。 * ・スレッドテーブルはサブスレッドから操作してはならない。 * ルール: * (1)arr[i]==NULL の時、arr[i] はサブスレッドを保持していない。 * また、過去にサブスレッドを保持していた場合は同期済である。 * (2)arr[i]!=NULL の時、arr[i] は同期前のサブスレッドを保持している。 */ /* 【必須】スレッドテーブルの初期化 * ・必ずメインスレッドの最初に呼ぶこと。 */ void my_thread_table_init( my_thread_table *mtt /* IN/OUT: スレッドテーブル(呼び出し元で領域確保する) */ ,int num /* IN:スレッドテーブルのサイズ */ , apr_pool_t *pool /* OUT:メモリプール */ ) { if (!mtt) { return; } if (num<1) { return; } mtt->num = num; mtt->pool = pool; mtt->index = 0; mtt->arr = (apr_thread_t**)apr_palloc(mtt->pool, sizeof(apr_thread_t*) * mtt->num); memset(mtt->arr, 0, sizeof(apr_thread_t*) * mtt->num); apr_threadattr_create(& mtt->attr, mtt->pool); /* デフォルトのスレッド属性の生成 */ } /* スレッドの生成 * 返り値: * 成功時には APR_SUCCESS。 */ apr_status_t my_thread_create ( my_thread_table *mtt /* IN:スレッドテーブル */ , apr_thread_t **thd /* OUT:生成したサブスレッドのスレッドハンドル */ , apr_thread_start_t func /* IN:サブスレッドが処理する関数 */ , void *data /* IN:サブスレッドが処理する関数で使うデータ */ ) { apr_status_t rv = APR_SUCCESS; char error_buf[32]; /* スレッドテーブルのインデクス変数は次の位置を指している。 */ /* スレッドテーブルの次の位置がヌルでない=サブスレッドは未同期(ルール(2)) */ if (mtt->arr[mtt->index]) { /* サブスレッドの同期 */ rv = apr_thread_join(&rv, mtt->arr[mtt->index]); if (rv != APR_SUCCESS) { /* 同期に失敗… */ if(1)printf("ERROR: apr_thread_join: %s\n", apr_strerror(rv, error_buf, sizeof(error_buf))); /* スレッドテーブルのインデックス変数を次の位置に。 * 理由:このエラーで呼び出し元が処理を終わらせてくれればよいが、 * また呼ばれた時に同じarr[index]に対してapr_thread_joinする。 * もしこのarr[index]が指すスレッドの異常が原因でエラーが発生 * していたとすると、再度同じエラーが発生する可能性があるので、次の * 位置に変更しておく。 * ただし、この対処は問題を先送りしてるだけかもしれない。 */ mtt->index = (mtt->index+1) % mtt->num; return rv; } /* 同期したサブスレッドのスレッドテーブル中のレコードをヌルに(ルール(1)) */ mtt->arr[mtt->index] = NULL; } /* APR でスレッド生成 */ rv = apr_thread_create(& mtt->arr[mtt->index], mtt->attr, func, data, mtt->pool); if (rv == APR_SUCCESS) { *thd = mtt->arr[mtt->index]; /* スレッドテーブルのインデックス変数を次の位置に */ mtt->index = (mtt->index+1) % mtt->num; } if (rv != APR_SUCCESS) { if(1)printf("%s\n", apr_strerror(rv, error_buf, sizeof(error_buf))); } return rv; } /* 【必須】スレッドテーブルのリセット * ・スレッドテーブルが保持する全サブスレッドの同期をしてからスレッドテーブルをリセットする。 * ・メインスレッドで最後に必ず呼ぶこと。 * 返り値: * 成功時には APR_SUCCESS。 */ apr_status_t my_thread_table_clear ( my_thread_table *mtt /* IN:スレッドテーブル */ ) { apr_status_t rv = APR_SUCCESS; int i=0; if (!mtt) { return APR_SUCCESS; } for (i=0; inum; i++) { if (mtt->arr[i]) { rv = apr_thread_join(&rv, mtt->arr[i]); if (rv != APR_SUCCESS) { char error_buf[32]; if(1) fprintf(stderr, "ERRPR: apr_thread_join: %s\n",apr_strerror(rv, error_buf, sizeof(error_buf))); /* return rv; */ /* ループを抜けたいところだが、残りのサブスレッドの * 同期が気になるのでループを継続する。 */ } mtt->arr[i] = NULL; } } /* スレッドテーブルをリセット */ mtt->arr = NULL; mtt->num = 0; mtt->index = 0; mtt->attr = NULL; mtt->pool = NULL; return rv; }