Help us understand the problem. What is going on with this article?

__thread で指定した変数の領域はスレッド終了時に開放されるのか? -> できるだけ使いまわすようです

More than 5 years have passed since last update.

__thread キーワード

C++11 以前に処理系が実装していたスレッドローカルストレージ (以下 TLS) のためのキーワード. 動的初期化は行えないため, 静的変数に付与して使用する. MSVC なら __declspec(thread).

疑問

スレッドが終了した時に __thread を使用して確保された領域はどうなるのか? 開放されずにメモリリークになったりするのか?

検証

tls_sample.cpp
#include <iostream>
#include <set>
#include <thread>

static std::set<int*> tls_set__;
static __thread int tls__[(1 << 20) / sizeof(int)];

struct Worker {
  int i;
  Worker(int i) : i(i) {}
  void operator()() {
    tls_set__.insert(tls__);
    *tls__ = i;
    std::this_thread::sleep_for(std::chrono::nanoseconds(1));
  }
};

void TLSTest() {
  int i_max = 1 << 10, j_max = 256;
  std::vector<std::thread> threads(i_max);
  for (int i = 0; i < i_max; i += j_max) {
    // スレッドを j_max 個作成
    for (int j = 0; j < j_max; ++j) {
      threads[i + j] = std::thread(Worker(i));
    }
    for (int j = 0; j < j_max; ++j) {
      threads[i + j].join();
    }
  }
  std::cout << tls_set__.size() << std::endl;
}

int main() {
  TLSTest();
  return 0;
}
/*実行結果
142
*/

作成したスレッド総数より TLS の数が少ないので, 使われなくなった TLS は回収されて使いまわされるように見える.
スレッド関数内の sleep 時間を伸ばすなどして同時に生きているスレッド数を上げると, TLS 数も増加した.
あまりにも大きなサイズの TLS をたくさんのスレッドで確保すれば静的領域を使い切るかもしれない.

静的領域の大きさは固定なはずだが、TLS に使われる領域はどのように用意している?

追検証(VC++で)

tls_sample2.cpp
#include <iostream>

int main() {
#define PRINTP(x) std::cout << #x << " : " << x << "(" << &x << ")" << std::endl;
  static int static__[1 << 10] = { 1 };
  static __declspec(thread) int tls__[1 << 10] = { 10 };
  static int stack[1 << 10] = { 100 };
  int* heap = new int[1 << 10]; heap[0] = 1000;

  PRINTP(static__[0]);
  PRINTP(tls__[0]);
  PRINTP(stack[0]);
  PRINTP(heap[0]);

  return 0;
}
/* 実行結果
static__[0] : 1(00007FF78FF59000)
tls__[0] : 10(0000004D144640E0)
stack[0] : 100(00007FF78FF5A200)
heap[0] : 1000(0000004D1446EA00)
*/

変数のアドレスを見るに, TLS は実はヒープ領域に確保されているようだ. OSX 上で Clang を使って実行しても同様の結果が得られた.

参考

http://docs.oracle.com/cd/E19205-01/820-1209/bjabr/index.html

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away