VC++2013とboost1.55のスレッドとvolatile修飾子について

 VC++2010(まで?)では、スレッドと、スレッドワーカー(ここではファンクタ)が保持する変数へのアクセスについて、とある禁断の手法が使えていた。
 それは、ワーカーのメンバー変数にvolatile修飾子をつけることで、コンパイラの最適化を抑止し、最新の値をどのスレッドからでも読み書きできるようにすることで、ワーカーのメンバー変数を簡単に読んだり変更したりし、フラグの制御などに使うという手法だ。

 これは、コンパイラオプションやターゲットプラットフォームによって挙動が変わるため、単一環境に絞って使う以外ではもちろん非推奨だし、単一環境で開発するにしても推奨できる方法ではなく、エレガントではない。もちろん、スレッドワーカーのメンバー変数をこれぐらい簡単に読み書きできる言語というものがもっともエレガントなのだろうが、C++はそのようには出来ていない。ただこの方法は、とてもポータブルなので使いたくなってしまう。
 だが、VC++2013とboost1.55で試したところ、どうやらこの禁断の手法はデフォルトでは使えないようだ。コンパイラオプション等によってはできるのかもしれないが、試していない。
 まぁ、この方法を禁止することはいいことなんじゃないだろうか。

 で、代替として何を使うのか、ということなのだが、boost::threadに用意されているinterruption系のプリミティブを使う。もっとも安易な使い方としては。

 1.スレッドルーチン内(ワーカーのスレッド用関数)の任意の位置に、this_thread::interruption_point関数を配置。
 2.別スレッド(メインスレッド等)から、thread::interrupt関数を呼ぶ。

 これだけ。ただし、これだとワーカー内でのリソース解放等をうまく行うために、interruption_pointをどこに配置するか悩むことになる上に、場合によってはジレンマが発生し、配置場所を決められないということになるだろう。なので、この方法でスレッドに割り込み終了させるときは、例として、

  • 割り込みが成功し、thread::joinが呼ばれた後に、ワーカーの後始末処理を実行する。
    • 普通の感覚だと、ワーカースレッド内で終了前に後始末処理を行いたいところだが、割り込みによって終了させる場合、下記に示すような特別な機構を用意しないと難しいと思うので、簡単に行えればよいときはこういったもので良いだろう。
  • スレッド管理機構(クラス等)を作り、 this_thread::at_thread_exitで登録したスレッド終了時呼び出し関数において、スレッド管理機構に終了しようとしているスレッドIDを渡し、そのIDを元に目的のワーカーを探し、終了処理をさせる。

といった工夫が必要だろう。そんなんじゃなくてもっといいのあるわという人はそれで。

 this_thread::at_thread_exitで登録出来るスレッド終了時関数が、現在の理解では「void f(void)」型しか受け付けないようで、なんだか気が利かないなぁという印象。