読者です 読者をやめる 読者になる 読者になる

自由課題

学んだり、考えたり、試したりしたこと。

makecontext関数でコルーチンを実装してみる

C

ユーザレベルでコンテキストの切り替えを行う関数としてmakecontextという関数があります(ここでいうコンテキストはこれです)。 これを使うとpthreadやプロセスを利用せずに処理の流れを制御できます。
車輪の再発明感がかなりありますが、この関数と関連する関数を使って簡単なコルーチンライブラリを実装してみました。

レポジトリは以下です。
https://github.com/kimito/libcr

このライブラリを使ったサンプルコードは以下です。使い方としては、create_context_for()でコルーチンを作成して、resume()でコルーチン側に制御を移します。コルーチン内ではyield()を読み出すことにより制御を戻します。

#include<stdio.h>
#include<stdlib.h>
#include"cr.h"

int i = 0;

void func()
{
  int j = 3;

  i++;

  yield();

  i+=2;
  j++;

  printf("j = %d\n", j);

  yield();

  printf("never come\n", j);
}


int main(int argc, char *argv[]){
  cr_context *ctx_func = create_context_for( func );

  if( !ctx_func ){
    return -1;
  }

  printf("start : i = %d\n", i);

  resume( ctx_func );

  printf("i = %d\n", i);

  resume( ctx_func );
  
  printf("i = %d\n", i);

  destroy_context( ctx_func );

  return 0;
}

実行結果は以下です。
func()内で確保したローカル変数の状態も保持しながらコンテキストスイッチを繰り返していることがわかります。

start : i = 0
i = 1
j = 4
i = 3

最後に言うのもなんですが、makecontext関数は移植性が悪いらしく、最近のPOSIX規格からは削除されているそうです。残念。

ちなみに上記のサンプルはCentOS 6.5で動作することを確認しました。なので少なくともlinux(というかglibc)では使えそうです。
時間があったらもう少しいじります。