« OSK でマルチスレッド | トップページ | 自前のセマフォは案外たいへん(2) »

2018年7月11日 (水)

自前のセマフォは案外たいへん(1)

先の記事 で、自前のマルチスレッド化で遊んだことを書きましたが、それに続けてセマフォのコードも書いたことが有りました。ただ、そのコードを見直してみると不備な点が多々見られたので、今回修正版を考えることにします。簡単に出来ると思っていたら意外に手こずっているので、数回に分けてセマフォのコーディングを実況して行きます。なお、残念なことに、現在、 OSK の動くシステムを持っていないので、動作を確認することが出来ません。

OSK には排他制御にイベントというものが有りますが、これはセマフォと同じようなものです(後に、イベントとは別にセマフォが導入されたようです)。イベントはプロセス間で使われるので、システムコールとして実装されています。しかし、自前のマルチスレッドならば、ユーザーレベルで実装したセマフォでも排他制御が可能でしょう。ユーザーレベルならばオーバーヘッドが小さくて済みます。そんなセマフォを考えて行きましょう。

簡単のため、2進セマフォを考えることにします。2進セマフォはキューと同じものなので、以下のコードでは構造体 queue_t として扱われています。

typedef struct{
    signal_code   signal;
    int           first;
    int           last;
    int           size;
    char          lock;
    char          dmy;
    process_id    id[QUESIZE];
} queue_t;

dmy はただのパディングです。 id[] はセマフォを待っているスレッドのプロセス番号を格納する配列です(ここでのスレッドは実際はプロセス)。配列に入りきらない分はエラーを返すことにします。 signal はセマフォ待ちで眠っている状態から起こされる時のシグナルです。

セマフォは使用に先立ち初期化します。QUESIGQUESIZE は別途定義されているとします。 (2-2) はセマフォのシグナルハンドラーを登録しています。 _glob_data は大域変数のベースアドレスです。これは親スレッドの大域変数ではなく、当該スレッドの大域変数(言わばスレッド・ローカル・ストレージ)です。(いや、そうだと思います。実機が無いので動作確認出来ません。)

void sigcatch(int sig)
{
    mysig = sig;        /* (2-1) */
    _os_rte();
} /* end of sigcatch() */

error_code mtx_init(queue_t *que, int f_creat)
{
    if (f_creat){
        que->signal = QUESIG;
        que->size = QUESIZE;
    }
    return _os_intercept(sigcatch, _glob_data);    /* (2-2) */
} /* end of mtx_init() */

(2-1) はシグナルハンドラーが受け取ったシグナル番号をスレッド・ローカル・ストレージ内の mysig に代入しています。 (2-2) でシグナルハンドラーに _glob_data を渡しているので、シグナルハンドラーは _glob_data を大域変数のベースアドレスとして変数へアクセスしていると思います(未確認)。即ち、 mysig は当該スレッドのローカル・ストレージ内のものということになります。

- 以下続く -

« OSK でマルチスレッド | トップページ | 自前のセマフォは案外たいへん(2) »

プログラミング」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/584699/66930325

この記事へのトラックバック一覧です: 自前のセマフォは案外たいへん(1):

« OSK でマルチスレッド | トップページ | 自前のセマフォは案外たいへん(2) »