CodeZine(コードジン)

特集ページ一覧

pthreadについて(スレッド固有データ)

スレッド単体で管理できる情報の生成・管理方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/12/28 14:00
目次

7. スレッド固有データ(Thread Specific Data:TSD)

 スレッドはあくまでプロセスの一部である事は既に述べました。スレッドはプロセスとさまざまな情報が共有されています。1章でも述べましたが、スレッドが独立で管理できる情報、つまりスレッド固有なデータは下記のみです。

  • スタック
  • スレッドID ( pthread_t
  • シグナルマスク ( pthread_sigmask(3)) ※ signalについて 参照
  • 代替シグナルスタック ( sigaltstack(2)) ※ signalについて 参照
  • errno変数
  • スケジューリングのポリシーと優先度 ※ 別章参照

 上記以外の情報、例えばプロセスIDなどの各種IDやグローバルなデータはプロセス共有となっています。

 しかし、スレッドが使用できるメモリがスタックだけでは都合が悪い時もあります。例えばスレッド内から呼ばれる関数でエラー情報をグローバルな変数にセットする場合、その変数はスレッド固有でないと、エラー情報が上書かれてしまうなどの弊害が発生します。

 上記以外でスレッド固有なデータを取得するには別途方法があります。特にグローバルな変数に対して完全にスレッド固有な、スレッドにとってプライベートな領域を確保する方法について述べていきます。

7.1 リファレンス

 主にスレッド固有データの生成にかかわる関数は下記の通りです。より詳細についてはmanコマンド、もしくはココを参照してください。

  • int pthread_key_create( pthread_key_t * key, void ( *destr_function )( void * ));
  • スレッド固有データキーを初期化します。
    • pthread_key_t:スレッド固有データキー。このキーに対してスレッド固有情報を取得します。1回だけpthread_key_createを実行する必要があります。通常、pthread_onceを利用します。
    • destr_function:いわゆるデストラクタです。使用しない場合はNULLでも良いです。主な使用法は8.3で説明します。
  • int pthread_key_delete( pthread_key_t key );
  • スレッド固有データキーを削除します。
  • int pthread_setspecific( pthread_key_t key, const void * pointer );
  • スレッド固有データキーに対し、pointerの値を結びつけて管理します。つまりpointerの値をスレッド固有データにします。
  • void * pthread_getspecific( pthread_key_t key );
  • スレッド固有データキーが管理している値を取得します。戻り値がNULLの時は登録されていないので、その際はpthread_setspecificを使って登録します。

7.2 プログラム

 まず下記のサンプルを実行してください。

tsd_once.c 実行結果
guest $ ./tsd_once
pthread_getspecific is NULL!!
[thread 1] set tsd value 0x81be560
[thread 1] starting...
[thread 2] set tsd value 0x81be560
[thread 2] starting...
[thread 3] set tsd value 0x81be560
[thread 3] starting...
thread 3 done...
thread 3 done...
thread 3 done...
guest $

 実行すると3つのスレッドの情報が出力されますが、同じアドレスを参照している事が分かります。参照しているアドレスはグローバルな変数で、各スレッドが書き込みや参照をしています。最後にスレッドが終了する際に出力される情報は、最後に動いたスレッドによって上書かれている事が分かります。

 次のサンプルを試してみてください。

tsd_once_2nd.c 実行結果
guest $ ./tsd_once_2nd
initializing key
pthread_getspecific is NULL!!
[thread 1] set tsd value 0x9550560
[thread 1] starting...
pthread_getspecific is NULL!!
[thread 2] set tsd value 0x9550570
[thread 2] starting...
pthread_getspecific is NULL!!
[thread 3] set tsd value 0x9550580
[thread 3] starting...
thread 1 done...
thread 2 done...
thread 3 done...
guest $

 同様に実行すると、先ほどとは違って上書きされておらず固有のデータとして扱われているのが分かります。参照しているアドレスは先ほどと同じグローバルな変数で、各スレッドが書き込みや参照をしています。

 もう1つ、次のサンプルを試してみてください。

tsd_once_3rd.c 実行結果
guest $ ./tsd_once_3rd
pthread_getspecific is NULL!!
[thread 1] set tsd value 0x8969578
[thread 1] starting...
pthread_getspecific is NULL!!
[thread 2] set tsd value 0x8969588
[thread 2] starting...
pthread_getspecific is NULL!!
[thread 3] set tsd value 0x8969598
[thread 3] starting...
thread 1 done...
thread 2 done...
thread 3 done...
guest $

 これも同様に固有のデータとして扱われているのが分かります。このサンプルはtsd_once.cとほとんど同じで、一点だけ__threadキーワードが付加されいるだけです(動かない場合は環境が新しくないという事になります)。

guest $ diff tsd_once.c tsd_once_3rd.c
2,3c2,3
< gcc tsd_once.c -o tsd_once -W -Wall -g -lpthread
<  */
---
> gcc tsd_once_3rd.c -o tsd_once_3rd -W -Wall -g -lpthread
> */
13c13
< tsd_t * value = 0;
---
> __thread tsd_t * value = 0;
guest $

 __threadキーワードについては後述します。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:pthreadについて

もっと読む

著者プロフィール

  • 赤松 エイト(エイト)

    (株)DTSに勤てます。 WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。 mixiもやってまして、こちらは子育てとか日々の日記メインです。

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5