Garbage Collection

塵も積もれば山

目次

Blog 利用状況

ニュース

C++とかC#とか数学ネタを投下していく予定です。

[その他のページ]
日々の四方山話を綴った日記出水の日記帳

書庫

日記カテゴリ

[C++]繊維の遷移で消化不良

以前、Luaのコルーチンを紹介しました。
このコルーチンはマイクロスレッドやファイバーという名前で呼ばれることもあります。

C++がどんなに変態的なプログラムができたとしても、コルーチンは無理!と思ってたのですが、
CreateFiberという関数があるという話を聞いたので使ってみました。

#include "windows.h"

/* サブのファイバ用関数 */
VOID WINAPI SubFiber(void *mainfiber){
  /* 処理 */
  
  printf("衝撃のファーストブリット!!\n");
  SwitchToFiber(mainfiber);

  printf("撃滅のセカンドブリット!!\n");
  SwitchToFiber(mainfiber);

  printf("抹殺のラストブリット!!\n");
  SwitchToFiber(mainfiber);

  printf("終わり!\n");
}

/* メインのファイバ用関数 */
DWORD WINAPI MainFiber(void *){
  /* このスレッドをファイバに変換 */
  LPVOID pMainFiber = ConvertThreadToFiber(NULL);
  /* サブのファイバ作成 */
  LPVOID subFiber = CreateFiber(0, SubFiber, pMainFiber);

  printf("MainFiber:Start\n");
  for (;;){
    SwitchToFiber(subFiber);
    Sleep(1000);
  }
  printf("MainFiber:End\n");

  return(0);
}

/* メイン関数 */
int main(int argc, char *argv[]){
  HANDLE hThread;

  /* メインのファイバ用スレッド作成 */
  hThread = CreateThread(NULL, 0, MainFiber, NULL, 0, NULL);

  /* スレッドの終了まで待機 */
  WaitForSingleObject(hThread, INFINITE);

  /* 後処理 */
  CloseHandle(hThread);

  return(0);
}

<実行結果>
MainFiber:Start
衝撃のファーストブリット!!
撃滅のセカンドブリット!!
抹殺のラストブリット!!
終わり!

SwitchToFiberがいわゆるyieldなんですが…なんと、コルーチンのアドレスを必要とします。
Switchという名の通り、引数として渡したコルーチンに実行が移動します。

Luaのコルーチンは呼び出した関数に戻るわけですが…。
つまり、言語がスタックに置いて管理しているはずのリターンアドレスを自分で指定しているわけです。

そして、関数が終了すると…関数を受け持つスレッドが終了してしまいます。

ということは、リターンアドレスを使うことは一度もないです。
もしかしたら、リターンアドレスは破壊されていて、使えないのかもしれません。

関数の終了でスレッドそのものが終了、ということは、
もう使わなくなったファイバーはどうすればいいんでしょう。
一応、DestoryFiberという関数があるにはあるにはありますが、
自分自身で壊すわけにはいかないので、誰かに壊してもらう必要があるわけです。

実行結果を見てもらえばわかりますが、MainFiber:Endが出力されていません。
無限ループから脱出する術がないので出るわけがないのですが…。
同時にもうひとつ問題が起きています。

実は、MainFiber関数は処理としては終わらないまま、プログラムそのものが終了しています。
つまり、強制的に中断されているわけで、関数のデストラクタに当たるものが実行されてないのです。
MainFiberにクラスを実体宣言した場合、そのクラスのデストラクタは呼ばれません。

最後に実行され、コルーチンのスレッドが終了する契機になる関数以外では
RAIIを利用したプログラムはかけないことになります。

正直、CreateFiberは面白い関数ではありますが、実用的ではないでしょう。
予想通りというか、残念な結果です。

投稿日時 : 2009年3月11日 22:04

Feedback

# re: [C++]繊維の遷移で消化不良 2009/03/11 22:23 NyaRuRu

Fiber 中でのリソース破棄については,Win32 構造化例外を使う方法でリソースクリーンアップを行う方法をやねうらおさんが提案していた気がします.

あと,Win32 Fiber は元々 MSSQL Server のために入ったような機構です.ユーザモードスケジューラ (UMS) を作れるようにして,スケーラビリティの確保したいというのが本来の想定用途です.
コルーチン用の便利 API と思っていると痛い目にあいますのでご注意を.
http://d.hatena.ne.jp/NyaRuRu/20070529/p1

ちなみに Windows 7 に向けて,次世代 UMS が着々と準備中のようです.個人的にかなり期待しています.
http://blogs.msdn.com/nativeconcurrency/archive/2009/02/04/concurrency-runtime-and-windows-7.aspx
http://channel9.msdn.com/shows/Going+Deep/Dave-Probert-Inside-Windows-7-User-Mode-Scheduler-UMS/

# re: [C++]繊維の遷移で消化不良 2009/03/11 22:33 NyaRuRu

追記.

Windows XP (32-bit) 以前を非サポートにしていいなら,FlsAlloc のコールバックをリソース破棄に使えるかもしれません.
http://msdn.microsoft.com/en-us/library/ms682664.aspx

また,C# の yield return は,IDisposable を使ったコールバックでうまいことリソース破棄を行ってます.
http://d.hatena.ne.jp/NyaRuRu/20070331/p1

JavaScript や Python も,例外を使ってコルーチンの終了タイミングの通知を受けていたと記憶しています.

# re: [C++]繊維の遷移で消化不良 2009/03/12 13:06 aetos

> 一応、DestoryFiberという関数があるにはあるにはありますが、
> 自分自身で壊すわけにはいかないので、誰かに壊してもらう必要があるわけです。

CreateFiber したファイバに壊してもらえばいいんじゃないですか?
ConvertThreadToFiber で作った最初のファイバは ConvertFiberToThread で戻すことができます。

サブファイバは return してはいけないんだと思います。
だから FiberProc には戻り値がないんでしょう。
メインファイバはサブファイバで行うべき処理がこれ以上ないことを検出できるように作っておき、サブファイバはその末尾に何もしない無限ループを入れておくとか。

http://blogs.wankuma.com/shannon/archive/2008/03/11/127267.aspx

# re: [C++]繊維の遷移で消化不良 2009/03/13 7:06 出水

NyaRuRuさんのページ読んだ上で書かせてもらいました

STGの弾クラスをBulletMLみたいな記法でやるには、って所からスタートしているんで、
あんまり大げさなものが欲しいわけじゃないんですよね…

>aetosさん
マネージャクラスがないと運用するのは厳しいですね
少なくとも、これがコルーチンとして優れているとも思わないし、
私が欲しいのもこういうものじゃないです

# IpozmcnXimTsAOwKAUa 2011/12/13 18:06 http://www.birthcontrolremedy.com/birth-control/cl

Not bad post, but a lot of extra !!...

# I'm not sure exactly why but this blog is loading extremely slow for me. Is anyone else having this problem or is it a problem on my end? I'll check back later on and see if the problem still exists. 2019/04/05 0:13 I'm not sure exactly why but this blog is loading

I'm not sure exactly why but this blog is loading extremely slow for me.
Is anyone else having this problem or is it a problem on my end?
I'll check back later on and see if the problem still exists.

タイトル
名前
Url
コメント