計算と描画のからくり
黄ばんだプリントアウトに触発されて腕試しを兼ねてマンデルブロ集合作図アプリケーションをこしらえました(図2)。添付したソリューションには.NET三大言語:C#, VB.NET そして C++/CLI によるプロジェクトを納めてあります。
それではマンデルブロ集合を計算機内に住むコビトさんに描いてもらうための道具を用意しましょう、方眼紙と色鉛筆のセットです。
まず方眼紙。ディスプレイ上の平面はpixelと呼ばれる小さなマス目を縦横にみっちり並べた、まさに方眼紙です。座標の取り方がちょいとヘンテコで左上隅を起点(0,0)とし、右方向/下方向がそれぞれX軸/Y軸の増加方向となります。幅W,高さHの方眼紙の左上隅が(0,0)、右下隅が(W-1,H- 1)となりますね。この方眼紙上の点(X,Y)を、その点と対応する複素数 x+yiに変換しなくてはなりません。加えて点(X,Y)を塗り潰す機能、方眼紙全体を画面に描画する機能を与えることにします。
そして色鉛筆のセット。今回は贅沢にも512色の色鉛筆を用意します。色鉛筆それぞれに0~511の番号を振り、与えられたn番目の色(ただしn < 0 のときは必ず"黒")を返します。
コビトさんは方眼紙の各点についてひとつずつ前章の疑似コードで述べた計算を行い、その結果に応じた色を色鉛筆セットから手に入れて方眼紙に打点します。
このアプリケーションの中では二人のコビトさんが仕事をします。一人は電卓片手に黙々と計算する計算コビト。もう一人は計算コビトの求めた結果に基づいて方眼紙を塗り潰す絵描きコビトです。絵描きコビトは一定期間ごとに発せられるタイマーのアラームを契機に方眼紙全体を画面に描画する役目も持っています。二人のコビトさんと方眼紙、色鉛筆セット相互の関係をユースケースっぽく描いてみました(図3)。
二人のコビトさんはひとつの方眼紙にアクセスします。計算コビトは方眼紙の目盛を読むし、絵描きコビトは方眼紙を画面に表示しますからね。このとき二人のアクセスが衝突しないよう排他制御を行いましょう。
MandelbrotPlotter と MainForm は SectionPaper 内の Bitmap に非同期にアクセスします。このとき一方がアクセスしている最中に他方がアクセスすることがないよう排他制御を行わなければなりません。C# では lock、VB.NET では SyncLock 構文で排他制御が可能となります:
// C#
lock ( target ) {
targetに対するアクセス
}
' VB.NET SyncLock target targetに対するアクセス End SyncLock
C++/CLI は lock, SyncLock に相当する構文を持ち合わせていません。lockを用いたC#コードをコンパイルし、ildasmでILレベルで逆アセンブルしてみると、 System.Threading.MonitorのEnter/Exitメソッドで実現していることが判明したので、同機能の小さなクラス MonitorLock を作りました:
class MonitorLock {
private:
gcroot<System::Object^> target_;
public:
MonitorLock(System::Object^ t) : target_(t)
{ System::Threading::Monitor::Enter(target_); }
~MonitorLock()
{ System::Threading::Monitor::Exit(target_); }
};
MonitorLockはコンストラクト時にEnter/デストラクト時にExitしてくれるので、これを使えば以下のようなコードで排他制御ができます。
// C++/CLI
{
MonitoLock lock(target);
targetに対するアクセス
}


