2011/06/28


ダウンロード配布物となっている mingw の c++config.h では /* Define if gthreads library is available. */
/* #undef _GLIBCXX_HAS_GTHREADS */
となっていて、下記の様なthreadを使ったコードはコンパイル出来ないのですが #include <atomic>
#include <thread>
#include <iostream>

std::mutex m ;
int x ; 

void thread()
{
    std::lock_guard<std::mutex> guard(m) ;
    ++x ; // 非アトミック操作
}

int main()
{
    x = 0 ; // 初期値0

    std::thread A( thread ) ;
    std::thread B( thread ) ;

    A.join() ; B.join() ;

    std::cout << x << std::endl ; // 2であるべき
}
本の虫: C++0xのマルチスレッドとデータ競合が非常に難しい

「バリアー!」「デュクシ!」「ちょっ、お前、オレ、バリアー張...

http://cpplover.blogspot.com/2011/06/c0x.html
手を加えてやる事でビルド出来る事が分かった。まずはオプションを上書きしてやる。 #define _GLIBCXX_HAS_GTHREADS 1
#define _GLIBCXX__PTHREADS 1
#define _POSIX_TIMEOUTS 1
次に、gthreadsが内部処理の為に定義しているスレッド識別子による比較関数を定義する #include <pthread.h>
inline bool
operator<(const pthread_t& lhs, const pthread_t& rhs) { 
  return lhs < rhs;
}
この状態でとりあえずコンパイルは出来る。ただしgthreads無効でビルドされているのでスレッド操作関数の実体が無い。そこでthread.ccからコードを拝借する。 namespace std
{
  namespace
  {
    extern "C" void*
    execute_native_thread_routine(void* __p)
    {
      thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
      thread::__shared_base_type __local;
      __local.swap(__t->_M_this_ptr);

      __try
        {
          __t->_M_run();
        }
      __catch(...)
        {
          std::terminate();
        }

      return 0;
    }
  }
  void
  thread::_M_start_thread(__shared_base_type __b)
  {
    if (!__gthread_active_p())
      __throw_system_error(int(errc::operation_not_permitted));

    __b->_M_this_ptr = __b;
    int __e = __gthread_create(&_M_id._M_thread,
                               &execute_native_thread_routine, __b.get());
    if (__e)
    {
      __b->_M_this_ptr.reset();
      __throw_system_error(__e);
    }
  }
  void
  thread::join()
  {
    int __e = EINVAL;

    if (_M_id != id())
      __e = __gthread_join(_M_id._M_thread, 0);

    if (__e)
      __throw_system_error(__e);

    _M_id = id();
  }
}
全体のソースだとこんな感じ。 // {{{
// vi:set ts=8 sts=2 sw=2 tw=0:
// vim:fdm=marker fdl=0 fdc=0 fdo+=jump,search:
// vim:fdt=substitute(getline(v\:foldstart),'\\(.\*\\){\\{3}','\\1',''):
#define _GLIBCXX_HAS_GTHREADS 1
#define _GLIBCXX__PTHREADS 1
#define _POSIX_TIMEOUTS 1
#include <pthread.h>
inline bool
operator<(const pthread_t& lhs, const pthread_t& rhs) { 
  return lhs < rhs;
}
// }}}

#include <atomic>
#include <thread>
#include <iostream>

// {{{
namespace std
{
  namespace
  {
    extern "C" void*
    execute_native_thread_routine(void* __p)
    {
      thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
      thread::__shared_base_type __local;
      __local.swap(__t->_M_this_ptr);

      __try
        {
          __t->_M_run();
        }
      __catch(...)
        {
          std::terminate();
        }

      return 0;
    }
  }
  void
  thread::_M_start_thread(__shared_base_type __b)
  {
    if (!__gthread_active_p())
      __throw_system_error(int(errc::operation_not_permitted));

    __b->_M_this_ptr = __b;
    int __e = __gthread_create(&_M_id._M_thread,
                               &execute_native_thread_routine, __b.get());
    if (__e)
    {
      __b->_M_this_ptr.reset();
      __throw_system_error(__e);
    }
  }
  void
  thread::join()
  {
    int __e = EINVAL;

    if (_M_id != id())
      __e = __gthread_join(_M_id._M_thread, 0);

    if (__e)
      __throw_system_error(__e);

    _M_id = id();
  }
}
// }}}

std::mutex m ;
int x ; 

void thread()
{
    std::lock_guard<std::mutex> guard(m) ;
    ++x ; // 非アトミック操作
}

int main()
{
    x = 0 ; // 初期値0

    std::thread A( thread ) ;
    std::thread B( thread ) ;

    A.join() ; B.join() ;

    std::cout << x << std::endl ; // 2であるべき
}
これ、vimmerならfoldを使ってやれば //                                                                               

#include <atomic>
#include <thread>
#include <iostream>

//                                                                               

int main() {
  std::mutex m;
  int x = 0;

  std::thread A([&] {
    for (int n = 0; n < 100; n++)  {
      std::lock_guard<std::mutex> guard(m);
      ++x;
      std::cout << x << std::endl;
    }
  });
  std::thread B([&] {
    for (int n = 0; n < 100; n++)  {
      std::lock_guard<std::mutex> guard(m);
      ++x;
      std::cout << x << std::endl;
    }
  });

  A.join();
  B.join();
}

こんな風に見えてちょっとはマシになる。これでmingw使ってthreadなプログラミングが出来ますね!
lambda使えばこんなのも出来て、たのしーーーー!

#include <atomic>
#include <thread>
#include <iostream>

int main() {
  std::mutex m;
  int x = 0;

  std::thread A([&] {
    for (int n = 0; n < 100; n++)  {
      std::lock_guard<std::mutex> guard(m);
      ++x;
      std::cout << x << std::endl;
    }
  });
  std::thread B([&] {
    for (int n = 0; n < 100; n++)  {
      std::lock_guard<std::mutex> guard(m);
      ++x;
      std::cout << x << std::endl;
    }
  });

  A.join();
  B.join();
}

Posted at by



2011/04/05


こりゃ出番だ!...と思ったとか、思わなかったとか...
()()で呼び出せるJavaScriptのネスト関数の活用法を思いついた - あと味

()()で呼び出すネスト関数の活用方法を考えたのですが、考えて出した答えがこれです。

http://d.hatena.ne.jp/jdg/20091020/1256042918
関数ポインタとか、operator()でもいいんだけど、リテラルを使いたくなかったのでマクロで...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define eq(x,y) !strcmp(x,y)
#define X(x) oppai(#x);
#define _(x) oppai(#x); X
void oppai(const char* rhs) {
  static const char* lhs = NULL;
  if (!lhs) lhs = rhs;
  else { puts(
      eq(lhs,"・")&&eq(rhs,"・")? "ハリのあるおっぱい" :
      eq(lhs,".")&&eq(rhs,"." )? "垂れ気味のおっぱい" :
      eq(lhs,"◎")&&eq(rhs,"◎" )? "立体的なおっぱい" :
      eq(lhs,"○")&&eq(rhs,"○" )? "乳輪が大きいおっぱい" :
      eq(lhs,"●")&&eq(rhs,"●" )? "乳輪が大きく、黒いおっぱい" :
      eq(lhs,"。")&&eq(rhs,"。" )? "色が薄く、左向きのおっぱい" :
      "引数には乳首しか受け入れません"
    );
    lhs = NULL;
  }
}


int main(void) {
  _(・)(・) // ハリのあるおっぱい
  _(.)(.)   // 垂れ気味のおっぱい
  _(◎)(◎) // 立派なおっぱい
  _(○)(○) // 乳輪が大きいおっぱい
  _(●)(●) // 乳輪が大きく、黒いおっぱい
  _(。)(。) // 色が薄く、左向きのおっぱい
  return 0;
}
これでいつでもC言語を書きながら、おっぱいを眺められますね!
Posted at by



2011/03/25


V8 JavaScript Engine 最近どのブログでも node.js ばかりでもう飽き飽きしてる皆さんこんばんわ。
node.js 面白いですよね!ェ

node.js ってアプリケーションを作る側(つまりライブラリを使う側)からすると、Web周りの便利なライブラリが既に色々あって、そのライブラリが一体どうやって動いてるのか気にすることってあんまり無いかと思います。

pure javascriptな物ならばコードを読むのは簡単です。ただしやれる事に限りがあります。node.js はGoogle製のJavaScript Engineであるv8をベースに作られているのですが、このv8はアプリケーションに組み込むのに適した構成になっていて、関数テンプレートやインスタンス、プロトタイプという各機能がC++のクラステンプレートで上手く表現出来ているライブラリです。Spidermonkeyも確かに扱うのは簡単なのですが、僕からすると若干C言語臭いというか、JavaScriptとC++との繋ぎが泥臭い感じがしています。
実際、Spidermonkeyを使ったembedがどの様になるかは先日phantomjsのGTK+版であるspecterjsを書いた時のコードを見てもらえると分かるかと思いますが、C言語からJavaScriptの型変換がいかにもフィルタ関数ぽく見えてしまいます。

今日はその辺りを上手く見せているv8で、どうやってembedを行うかを紹介して見ようと思います。

以下の手順にそっていけば、きっと貴方もv8で自作の埋め込みオブジェクトを実装出来る様になるでしょう。

まずv8をインストールしましょう。
v8 - V8 JavaScript Engine - Google Project Hosting

V8 JavaScript EngineV8 is Google's open source JavaScript engine.

http://code.google.com/p/v8/
subversionで以下の様にコードを取得します。 # svn checkout http://v8.googlecode.com/svn/trunk/ v8 ビルドにはSConsが必要です。ubuntuならばaptで、windowsならばオフィシャルからインストーラをダウンロードしてインストールするのが無難かと思います。
SCons: A software construction tool

What makes SCons better? Configuration files are Python scripts--use the power of a real programming...

http://www.scons.org/
参考にするのにまず最初にsamples/shell.ccを見るのをお勧めします。
JavaScriptの対話コンソールプログラムなのですが、グローバルやコンテキスト、関数wrap、スクリプト実行のやり方が分かるかと思います。
コンパイルは # scons sample=shell を実行します。
ここにどうやって自分のオブジェクトを埋め込んでいくかが今回の本筋です。
まず、適当にクラスを作ります。これはv8には依存させません。
class FooImpl {
private:
  std::string value;
public:
  FooImpl() {}
  ~FooImpl() {}
  void SetValue(const std::string v) {
    this->value = v;
  }
  const std::string GetValue() const {
    return this->value;
  }
  void ConcatValue(const std::string v) {
    this->value += v;
  }
};
簡単な文字列を内包するクラスです。GetValue()/SetValue()というアクセサ、ConcatValue()というメソッドを持っています。
これをv8からFooというクラスで表現します。ベースは先ほどのshellに埋め込みます。
まずクラステンプレートを作ります。JavaScriptなのでクラスとは言えど関数テンプレートでしかありません。
// Make class template
v8::Local<v8::FunctionTemplate> clazz = v8::FunctionTemplate::New(Foo_Construct);
clazz->SetClassName(v8::String::New("Foo"));
ここでNewに渡しているFoo_Constructが、v8上で var f = new Foo(); と実行した際に呼ばれるコールバック関数です(関数名は分かりやすくしているだけなのでより良い関数名を付けた方がいいでしょう)。こちらは後で説明します。
次にインスタンステンプレートです。インスタンス化された際の形状を定義します。
// Make instance template
v8::Local<v8::ObjectTemplate> instanceTmpl = clazz->InstanceTemplate();
instanceTmpl->SetInternalFieldCount(1); // Store internal
instanceTmpl->SetAccessor(v8::String::New("value"), Foo_getValue, Foo_setValue); // Accessor
SetInternalFieldCountは何を意味しているかというと、このクラスに内部フィールドを幾つ持たせられるかを教えています。そうです。FooImplのインスタンスですね。
SetAccessorはアクセサ名とゲッタ・セッタ(Foo_getValue()/Foo_setValue())を渡してあげます。こちらも先ほどのFoo_Constructと同様にコールバック関数になっています。これについても後で説明します。
そしてプロトタイプテンプレートを作ります。
// Make method
v8::Local<v8::ObjectTemplate> prototypeTmpl = clazz->PrototypeTemplate();
prototypeTmpl->Set("concat", v8::FunctionTemplate::New(Foo_concat));
global->Set(v8::String::New("Foo"), clazz);
インスタンスとプロトタイプがC++上でも綺麗に色分けされていますね。ここではconcatというメソッドを実装しています。これまでと同様にFoo_concatというコールバック関数を指定します。
最後にglobalに対してFooという名前で関数テンプレートを登録します。
v8との繋ぎ目は以上で完了です。

さて、個々のコールバックを実装して行きましょう。まずコンストラクタ。
static v8::Handle<v8::Value> Foo_Construct(const v8::Arguments& args) {
  FooImpl* foo = new FooImpl();
  printf("construct Foo: %p\n", foo);
  v8::Local<v8::Object> thisObject = args.This();
  thisObject->SetInternalField(0, v8::External::New(foo));
  v8::Persistent<v8::Object> holder = v8::Persistent<v8::Object>::New(thisObject);
  holder.MakeWeak(foo, Foo_Dispose);
  return thisObject;
}
FooImplのインスタンスをSetInternalFieldで設定しています。
このthisをargsから取る辺りも、JavaScriptに似せてあって良いですね。ちなみにArguments::Callee()も存在します。
さて、ここでv8::Persistent::MakeWeak()を呼び出していますね。これはこのインスタンスを保持する予定のホールダーを意味していて、そのホールダーに対してインスタンスが弱参照である事を教えています。またその際、デストラクタをコールバックとして指定しています。
ではデストラクタを実装しましょう。
static void Foo_Dispose(v8::Persistent<v8::Value> handle, void* parameter) {
  FooImpl* foo = static_cast<FooImpl*>(parameter);
  printf("destruct Foo: %p\n", foo);
  delete foo;
  handle.Dispose();
}
MakeWeak呼び出しの第一引数がparameterで渡ってきますので、FooImplのインスタンスを得ます。ここでは単にdeleteしていますが、特別な後処理があるならばここで実装します。
同様の手順でアクセサコールバックを実装します。
static v8::Handle<v8::Value> Foo_getValue(v8::Local<v8::String> propertyName, const v8::AccessorInfo& info) {
  FooImpl* foo = static_cast<FooImpl*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
  return v8::String::New(foo->GetValue().c_str());
}

static void Foo_setValue(v8::Local<v8::String> propertyName, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
  FooImpl* foo = static_cast<FooImpl*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
  v8::String::Utf8Value utf8str(value);
  foo->SetValue(*utf8str);
}
GetInternalFieldからコンストラクタで登録していたFooImplのインスタンスを取得します。中身は普通のC++の処理です。
ここまで来るとconcatメソッドも同じですね。
static v8::Handle<v8::Value> Foo_concat(const v8::Arguments& args) {
  FooImpl* foo = static_cast<FooImpl*>(v8::Local<v8::External>::Cast(args.This()->GetInternalField(0))->Value());
  v8::String::Utf8Value utf8str(args[0]);
  foo->ConcatValue(*utf8str);
  return v8::Undefined();
}
第一引数をStringとしてFooImpl::concatを呼び出しています。

以上です。ただこのshellはコンソールから文字列を読み取って実行するループが行われていますのでv8からすると常にbussy状態になっています。共有ライブラリとしてビルド(USING_V8_SHAREDを指定してビルド)していない限りはメインスレッド上で実行されてしまいます。つまりオブジェクトの生死管理が実行されません。なおUSING_V8_SHAREDを指定してビルドされていれば # ./shell --isolate --shell として実行すれば別スレッドとして実行されます。
以前は v8::internal::Heap::CollectAllGarbage(); という関数で強制GCを実施出来ましたが、最近ヘッダファイルから無くなりました。これはおそらく、スレッドが入り乱れても動作しなければならないv8上ではGCのタイミングはユーザが決めるべきではないとの判断だと思っています。その代わりにv8の開発ML上では以下のコードがFAQの様に良く出てきます。
while (!v8::V8::IdleNotification());
v8::V8::IdleNotificationの関数コメントには以下の様に書いてあります。   /**
   * Optional notification that the embedder is idle.
   * V8 uses the notification to reduce memory footprint.
   * This call can be used repeatedly if the embedder remains idle.
   * Returns true if the embedder should stop calling IdleNotification
   * until real work has been done.  This indicates that V8 has done
   * as much cleanup as it will be able to do.
   */
  static bool IdleNotification();
訳すと
組み込み側がアイドル状態であることを意味するオプションの通知。
V8 はメモリの証跡を減らす為に通知を使用します。
これは、組み込み側がアイドル状態である間は何度でも呼び出す事が出来ます。
実際の処理が完了するまでの間、組み込み側が IdleNotification を呼び出すべきでない場合には true を返します。
これは V8 が可能な限り多くのクリーンアップを、この時点で行っていた事を意味します。
なのでGCの動作確認を行うのであればshellのRunShellに以下の行を入れる事になります。 // The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
  printf("V8 version %s\n", v8::V8::GetVersion());
  static const int kBufferSize = 256;
  // Enter the execution environment before evaluating any code.
  v8::Context::Scope context_scope(context);
  while (true) {
    char buffer[kBufferSize];
    printf("> ");
    char* str = fgets(buffer, kBufferSize, stdin);
    if (str == NULLbreak;
    v8::HandleScope handle_scope;
    ExecuteString(v8::String::New(str),
                  v8::String::New("(shell)"),
                  true,
                  true);
    // Notify idle
    while (!v8::V8::IdleNotification());
  }
  printf("\n");
}
さぁ実行しましょう。
# ./shell 
V8 version 3.2.4.1
> var a = new Foo
construct Foo: 0x9526c98
> a.value

> a.value = "foo"
foo
> a.concat("bar")
> a.value
foobar
> a = null
null
destruct Foo: 0x9526c98

ちゃんと動いてますね。デストラクタもきちんと走ってます。
ここまでのコードを以下のGistに貼り付けておきます。
mattn's gist: 885688 — Gist

shell.cc

https://gist.github.com/885688
以上が v8 を使った基本的な embed となります。どうでしょうか?貴方も作れそうな気がしませんか?

ぜひチャレンジしてみて下さい。なお、だいぶ昔ですが v8 から twitter や wassr を操作出来る shell の改良物を作った事があったので参考URLとして記しておきます。
/lang/cplusplus/twitter-v8 – CodeRepos::Share – Trac

twitter-v8

http://coderepos.org/share/browser/lang/cplusplus/twitter-v8
面白い物が出来たらぜひ公開してみて下さい。
Posted at by