2014年9月16日火曜日

C++で無名関数を遅延実行する

C++でObjective-CのGCD(Grand Central Dispatch)のように無名関数を別スレッドで遅延実行することができれば便利なので、どうすればできるのか考えて実装してみました。

GCDをWindowsやLinuxのC++などで実行するライブラリ、XDispatchなどもあるのですが、C++にはARC(Automatic Reference Counting)が無い分、オブジェクトのdeleteなど、いろいろな制約があって微妙に使い勝手が違います。そこで少しずつGCDを自分で作ってGCDの技術を勉強してみようと思います。

まずC++のラムダ式から。C++のラムダ式だけだと見た目には似たようなことができるのですが、スレッッドやオブジェクトをARC管理していないので、オブジェクトの開放のタイミングと無名関数内でのキャプチャの解放タイミングが合わず、オブジェクトの相互更新とかスレッドのライフタイムの管理がなかなかうまくできません。

そこで以前紹介した、Googleがandroid用に作ったスマートポインタとC++のラムダ式を組み合わせて使ってみるとARCのようなことができるのではないかと思い、早速実験してみました。

やったー。予想通り値が5になりました。

あとは無名関数をスレッドで即実行するのではなくグローバルなキューに入れて実行すれば、CGDが簡単に作れるはず。


C++でスマートポインタとラムダ式を使うとオブジェクトのdeleteのタイミングを一切気にしなくてよいので、javaの無名クラスやObjective-Cのブロックみたいなことができて便利そう。


----------------
#include <stdio.h>

#include <functional>

//  Memory Debug
#if defined(_WIN32) && !defined(__GNUC__)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif /* _WIN32 */


#include "RefBase.h"
#include "Threads.h"


using namespace std;
using namespace android;


class MyThread :public Thread
{
public:
virtual ~MyThread();
MyThread(function<void()> f);
virtual bool threadLoop();
public:
function<void()> m_func;
};

MyThread::MyThread(function<void()>  func)
{
m_func=func;
}

MyThread::~MyThread()
{
}

bool MyThread::threadLoop()
{
if(m_func)m_func();
return false;
}


class A:public RefBase
{
public:
A();
virtual ~A();
void test();
void setVal(int a);
int getVal();
public:
int m_a;
};

A::A()
{
m_a=0;
printf("A::A\n");
}

A::~A()
{
printf("A::~A\n");
}
void A:: test()
{
}

void A::setVal(int a)
{
m_a=a;
}

int A::getVal()
{
return m_a;
}

int main()
{
#if defined(_WIN32) && !defined(__GNUC__)
// _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_WNDW);
// _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
// _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif


sp<MyThread> mt=NULL;
sp<A> c=NULL;
int i;

c=new A();
mt=new MyThread([=](){
int v;
v=c->getVal()+3;
c->setVal(v);
printf("v=%d\n",v);

});
i=c->getVal()+2;
c->setVal(i);
c=NULL;
mt->run();
mt->join();

return 0;
}






0 件のコメント:

コメントを投稿