Monthly Archives: September 2009

Grand Central Dispatchを試してみる。

Snow LeopardではOSの基礎部分にかなりの改良を加えたと、Appleはいいます。
その基礎部分の改良の目玉機能の一つであるGrand Central Dispatchは、マルチコアでのプログラミングを簡単に行うためのフレームワークを提供してくれます。

マルチコアでのプログラミングはいろいろと難しいことが多く自分は興味を持ったので、プログラムプレゼンテーションのネタに少し試してみることにしました。

すでに最初の一歩を踏み出された方がいます。
Grand Central Dispatch at mootoh.log
Grand Central Dispatch をためす at mootoh.log
Grand Central Dispatchを試してみる – 理想未来はどうなった?

dispatch_asyncというのは非同期に与えたブロックを実行するもので、
対してdispatch_syncというものは同期的にブロックを実行するものようです。

この同期、非同期というものを自分はきちんと理解していないのですが、Concurrency Programming Guildeというドキュメントによると。。。

dispatch_async

Submits a block for asynchronous execution on a dispatch queue and returns immediately.

dispatch_sync

Submits a block object for execution on a dispatch queue and waits synchronously until that block completes.

引用元: Grand Central Dispatch (GCD) Reference

dispatch_syncはブロックが終了するまで待ってるよという風に見えます。

上記のサンプルを参考にしつつ、ためしにこんなコードを書いてみました。

#include <dispatch/dispatch.h>
#include <iostream>
#include <stdio.h>
#include <unistd.h>

void c_hello(int count = 10)
{
	void (^hello)(int) = ^(int x)
	{
		printf("Hello, C World! %d\n", x);
	};

	for (int i = 0; i < count; ++i)
	{
		dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
					   ^{
						   hello(i);
					   });
	}
}

void cpp_hello(int count = 10)
{
	void (^hello)(int) = ^(int x)
	{
		std::cout << "Hello, C++ World! " << x << std::endl;
	};

	for (int i = 0; i < count; ++i)
	{
		dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
					   ^{
						   hello(i);
					   });
	}
}

int main (int argc, char * const argv[])
{
	c_hello(1000);
	cpp_hello(1000);

	std::cout << "done!" << std::endl;

	// sleep がないと処理が終了する前に return してしまう。
	sleep(5);
	
    return 0;
}

カリー化はブロックをブロックでくくればいいのでしょうか?

わざとCのprintfとC++のstd::coutの両方を書いてみました。
面白かったのが1000回ループをさせたときでした。
10回では起こりませんでしたが、回数が増えるにつれ、C++の方はこんな風にごちゃ混ぜになりました。

Hello, C++ World! Hello, C++ World! Hello, C++ World! 974975976977978

ちょっと考えてみると、<< 演算子で何個ものメソッドが入り組んでいる分、多数のスレッドが起動されるとこうなるのでしょう。 実際にプログラムプレゼンテーションで見せて、なにか簡単ないいサンプルがないと話してみたところ、g000001さん疑似並行処理 どう書く?orgという課題をやってみてはどうか?というアドバイスをいただきました。

これがその解答になるかと思います。

#include <dispatch/dispatch.h>
#include <stdio.h>
#include <unistd.h>

int main (int argc, char * const argv[])
{
    void (^alphabet)(int x) = ^(int x)
    {
        putchar('a' + x);
        putchar(' ');
    };

    void (^number)(int x) = ^(int x)
    {
        printf("%d ", x);
    };

    for (int i = 0; i < 26; ++i)
    {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{ alphabet(i); });
        dispatch_async(queue, ^{ number(i); });
    }

    printf("done!\n");
    sleep(5);
	
    return 0;
}

結果は次のようになって、アルファベットと数字が無事混ざって表示されました。

done!
a 0 b 1 c 2 d 3 e 4 f 5 g 6 h 7 i 8 j 9 k 10 l 11 m 12 n 13 o 14 p 15 q 16 r 17 s 18 t 19 u 20 v 21 w 22 x 23 y 24 z 25 

これからは共有リソースをどうやって扱うことができるのか調べたいところです。

P.S.
スレッド関連の用語を知らないので、適当に書いたところが多々あります。
うまく説明できないのが非常にもどかしいところです。