Monthly Archives: 3月 2014

C#コントロールの複数スレッドアクセス問題

C#のアプリ開発で嵌ったメモ書きです。

C#でフォームのコントロールを扱うとき、同一スレッドからアクセスする必要があります。
たとえば、以下のようにDataGridViewに別スレッドからアクセスすることを考えて見ます。

一見すると正常なコードに見えます。
異なるスレッドからのアクセスを考慮してDataGridViewには排他ロックをかけています。
オブジェクトのnullチェックや配列のサイズチェックもしっかり行っているため、問題無いように見えます。

しかし、これを数百回繰り返すと稀にNullReferenceExceptionやArgumentOutOfRangeExceptionが発生することがあります。

これはどういうことでしょうか。

異なるスレッドからアクセスすると、データの整合性が取れなくなる場合があるからです。
メインスレッドからDataGridViewオブジェクトの中身を書き換えている途中で
別のスレッドからアクセスされるためです。

したがって、前述このようなコードはメインスレッドからアクセスすることで発生しなくなります。

この例はあまり有用とは言えませんが、単純にメインスレッドで単純にアクセスさせるようにした例です。
これで前述の例外は発生しなくなります。

このようなマルチスレッド系のバグはなかなか気づきにくいため注意すべきです。

サイトデザイン変更しました

メインWebサイトのデザインを変更しました。
外観は以下のようになりました。

site-new

前回のグレーで淡い印象のデザインから一新、黒一色のコントラストの強いデザインにしました。

まだレイアウトや細部の作り込みが甘いため、
時間を見つけ次第少しずつ修正していくつもりです。

コンテンツもまだゲーム1本のみなので、これから少しずつ追加していく予定です。

作業は気まぐれになると思いますが、徐々にサイトを充実させていけたらと思います。

QNAP TS-869 Proをメモリ増設してみた

QNAP TS-869 Proのメモリ増設についての動作報告です。
実を申し上げると、今日のサーバメンテナンスでメモリ増設を行いました。

QNAP TurboNASシリーズはメモリ増設ができますが、
保障外のメモリでは相性が合わず正常動作しないことが多いです。
デフォルトで1GBのメモリが搭載されており、SO-DIMM DDR3の空きスロットにメモリを増設できます。
最大3GBまで増設が可能です。

駄目元で家に余っていたSAMSUNG製の4GBメモリ(m471b5273dh0-ch9)を装着して動作させました。

mem-samsung

結果は起動せず・・・
ブートの時点でフリーズしてしまいました。

仕方なくNAS専用メモリを購入することにしました。
購入したメモリはTEKWIND製の2GBメモリです。

mem-tekwind

今度はちゃんと起動して正常動作しました。
管理画面を見るとメモリが3GBになっているのを確認できます。

mem-size3gb

体感速度上の変化はありませんでしたが、これからサービスをどんどん立ち上げていくとなると
メモリが多くあったほうが何かと便利です。
メモリ使用量は1GBの時と変わらず500MB台でした。

使用していない領域はRAMディスクやキャッシュに使うなど使い道がありそうですね。

Mac版「Departure from the Void」開発着手

サイト上に公開中のオリジナルゲーム「Departure from the Void」のMac版の開発に着手いたしました。

私自身、Macに対する知識が非常に浅いため、開発環境やAPIの基本的な使い方から勉強しています。
以下、開発途中のスクリーンショットです。

dpc-mac

現状では画像を表示する部分までしか実装できていないため、ゲームのプレイは出来ません。
上記のスクリーンショットで表示している画像はやや歪んでいます・・・

開発環境にはXcode、グラフィックの描画にはOpenGLを用いています。
OpenGLの使い方はほぼ忘れてしまっている状態なので、何とかしなくては・・・と焦り気味な気持ちです。

ここしばらくはグラフィックやサウンド、その他Macのお作法的な勉強で時間が取られそうです。
完成までの道のりは長いですが、気長にやっていければと思っています。

C#のタスクキャンセル

C#でスレッドプールからタスクを実行するとき、
タスクを途中でキャンセルしたい場面も出てくるでしょう。

スレッドプールからタスクを実行するにはTaskFactory.StartNew()を用います。

TaskFactory.StartNew()メソッドによりタスクを実行するとき、
タスクを途中でキャンセルできるようにするには
第2引数にCancellationTokenを指定します。

これはCancellationTokenSource.Tokenフィールドとなります。

タスクにキャンセル要求を出すにはCancellationTokenSource.Cancel()メソッドを実行します。
これによりキャンセルフラグが立ちます。

タスク側では特定のタイミングでこのキャンセルフラグをチェックする必要があります。
キャンセルフラグはCancellationToken.IsCancellationRequestedフィールドです。
このフラグが立ったらタスク側はOperationCanceledException例外をスローするようにします。
したがって、フラグチェックから例外スローのコードは以下のようになるでしょう。

しかし、これをいちいち随所に書くのは手間なので、
以下のように一文で済ませてくれるメソッドが用意されています。

これをタスク内の特定の箇所に埋め込んでおきます。

タスクの呼び出し元ではキャンセル要求をした後にキャンセルされるまで待機する必要があります。
待機はTask.Wait()メソッドにより行います。
タスクがキャンセルされると呼び出し元スレッドで
AggregateException例外が発生するため、これをキャッチします。

タスクキャンセルを使ったコードは以下のようになります。

スレッドプールよりタスクを起動すると
タスクは0.5秒ごとにカウント値を出力します。

ここでユーザが文字列を入力するとキャンセル要求がタスク側に発行され
タスクはこれをチェックして終了します。

異なるスレッドのタスクを強制終了するのは大変危険ですが
このようなフラグチェックの仕組みを用いれば安全です。
C#に限らず他のプログラミング言語でも同様のことが言えるでしょう。

■参考サイト
タスクのキャンセル

WordPressとTwitterの連携

ブログとTwitterを使っていると、ブログの更新情報をTwitterに反映させたい人は少なくないのではないでしょうか。
私もその一人です。

今回はWordPressとTwitterの連携方法についてです。

個人的に以下の要件を満たす方法を探りました。

 ・ブログの記事を更新すると即座にTwitterに投稿内容が反映される
 ・予約投稿時でも正しく反映される
 ・短縮URLは使いたくない

上記すべてを満たすプラグインは見つかりませんでした。
しかし、プラグインのソースファイルを直接編集することで上記すべて満たすプラグインにTweetableがありました。
Tweetableは短縮URLしか使えませんが、後述する手順でブログのURLをそのまま使えるようになります。

もうひとつの候補のプラグインにWordTwitがありましたが、こちらは予約投稿で記事を更新すると何故かツイートに失敗してしまいます。
消去法的にTweetableになりました。

導入手順は以下の通りです。

1.Tweetableのインストール
以下サイトよりTweetableプラグインをダウンロードし、インストールします。

http://wordpress.org/plugins/tweetable/

ダウンロードしたzipファイルを解凍し、ご自身のWordPressのプラグインディレクトリ(ワードプレスディレクトリ/wp-content/plugins/)におきます。
その後、WordPressの管理画面より「Tweetable」プラグインを有効化します。

2.Treetableの設定
Tweetableの設定手順を書こうと思いましたが、以下サイト様にて丁寧な解説がなされています。
詳しくはそちらをご覧下さい。
(丸投げで申し訳ありません><)

http://www.seotemplate.biz/blog/wordpress-plug/2232/

私も上記サイトを参考に設定させていただきました。

3.独自URLの設定
Tweetableは短縮URLしか扱うことが出来ません。
短縮URLは便利ですが、これを提供するサービスが終了となるとアクセスできなくなってしまいます。
多少長くても独自ドメインのURLを使いたいという場合は、PHPファイルを直に書き換えて設定します。

設定方法は以下サイト様にて詳しく解説されておりました。
詳しくはそちらの手順を踏んでいただければ完了します。
(またまた丸投げで申し訳ありません><)

http://blog.nezweb.net/archives/69

上記サイトの手順を実施することで、以下のように独自URLで投稿されることを確認できました。(2014/3/27現在)

tweetable-url

Twitterの仕様が変わると従来の設定方法が使えなくなる可能性があるので、もしそうなった場合はこちらを疑ってみたほうがよいかもしれません。

■参考サイト
Tweetable – Twitterとの連携
Tweetableで短縮URLを使わない方法

C#におけるタイマースレッドの生存期間

C#ではスレッドやタスクを簡単に扱えるようになっています。
また、ガベージコレクタが走っており、不要なメモリ資源の回収も簡単に行えます。

しかし、これらの便利な機能があるが故に落とし穴も存在します。

例えば、以下のコードはメソッドの中でスレッドプールからタイマーを生成して実行する例です。

Windows7 64bit、Visual Studio 2013の環境では、アプリケーションが終了するまでカウント値が出力され続けます。
一方、以下のようにRunTimerメソッドの実行後に強制的にガベージコレクタを実行すると、カウント値の出力がとまります。

これは何故でしょうか?

RunThreadメソッドを抜けるとtaskオブジェクトはどこからも参照されなくなります。
ここで、C#のガベージコレクタが走り、参照されなくなったtaskオブジェクトをゴミとみなして解放されるようになります。
しかし、解放されるタイミングは実行環境に依存します。

上記の例ではプログラムがとても短かったので、ガベージコレクタを強制的に実行しない限りタイマースレッドの資源回収が行われなかったためです。
したがって、このようなコードを書くと後々で難解なバグに悩まされることになります。

解決策は、生成したスレッドを必ず何らかの方法で参照させ続けておくことです。
例で示したコードのタイマースレッドは、フィールドに参照を持たせておくことでガベージコレクタの実行後もカウント値が出力され続けます。

スレッドを実行するときはきちんと参照を保持しておくこと。
そして、スレッドを止めるときは明示的に止めることを意識しておけば問題ないと思います。

■参考サイト
Timer クラス
c# ファイナライザーの実行タイミング

Twitterアカウント設置しました

「from the void」の活動状況告知用のTwitterアカウントを設置しました。
アカウント名は@ftvoidです。

このブログやWebサイトの更新情報をはじめ、創作活動の近況報告やサーバのメンテナンス情報、その他お知らせ情報などをつぶやいていきたいと思います。
ご自由にフォロー・リムーブしていただいて構いません。
告知用のアカウントのため、フォローバックは今のところ考えていません。

このまま運用を続けていくかどうかはまだはっきりしていません。
ここしばらくは様子見で運用していきたいと思います。

C#のforeach文の展開について

C#のforeach文は配列をはじめ、列挙子やリストなどのさまざまなシーケンシャルな反復処理を簡潔に書くことができます。

このforeach文はコンパイル時に以下のようなコードに展開されます。

展開されたコードを見ると、collectionはGetEnumerator()メソッドを実装している必要がありそうです。
また、GetEnumerator()メソッドの戻り値型であるEはMoveNext()メソッドとenumerator.Currentプロパティを実装している必要がありそうです。

実際にこのような仕様になっています。

たとえば、フィボナッチ数列を表すクラスは以下のように実装すればforeach文で扱うことが出来ます。

■ソースコード

■実行結果

クラスの実装はやや手間がかかるかと思いますが、一度実装してしまえばこちらのものです。
ライブラリでもforeach文での使用が可能なクラスはたくさん有るので、どのような実装になっているか調べてみるのも面白いかもしれません。

■参考サイト
8.8.4 foreach ステートメント

ゲームのタスクシステム設計あれこれ

ゲームを進行させていくにあたって重要になるのが複数タスクの管理です。
俗にタスクシステムと呼ばれているものです。
タスクシステムの明確な定義はありませんが、たとえばキャラクタを移動させたり当たり判定させたり描画させたりといった処理の進行を管理するものだと解釈して差し支えないと思います。
これらのタスクを管理するためのクラス設計について考えてみました。

ゲームの進行で必要になる代表的な処理は以下のようになると思います。

 1.キャラクタの移動、回転
 2.キャラクタ同士との当たり判定
 3.キャラクタの描画
 4.効果音再生
 5.ファイル等の外部との非同期I/O処理

上記のうち、1~3はタイマーイベントで逐次呼び出される可能性があります。
4~5は1~3ほど頻度は高くないですが、不特定なタイミングで呼び出される可能性があります。
いずれにせよ、これらの処理は見かけ上平行して行う必要が出てくるでしょう。

また、処理の順番も重要で、キャラクタを移動してから描画するのと、描画してから移動するのではキャラクタの動きが異なってきます。
因みに、この順番は一般に前者が正しいです。
後者だと1フレームの遅れが出てしまうからです。

1~3の処理は1→2→3の順番で行う必要があります。
また、どれもタイマーイベントが発生したときに行う点で共通しているため、同じ基底クラスからの派生クラスとして実装すればよいでしょう。
したがって、1~3のタスクは以下のようなクラスになるでしょう。

そして、タイマーイベントの中で上記タスクを1~3の順番で実行します。

それほど複雑でないと思います。

さて、ここで問題になるのは4~5の処理の呼び出しです。
効果音はたとえばキャラクタ同士が衝突したときに衝突音を発生させたい場合があると思います。
ファイルI/Oの処理はゲームシナリオの切り替え時に途中結果を保存したり読み出したりしたい場合に必要になります。

これらの処理は1~3の処理に密接に関係してきます。
結論から言うと、これらも1つのタスクとしてみなすことが出来ます。
4、5の処理は3の描画処理の後に行うようにすればよいでしょう。

これでひとまず大枠は出来ました。
上記の処理はどれも似通った呼ばれ方をしていると思います。

上記の5つのタスクはそれぞれ特有の処理を受け持っています。
たとえば、MotionTaskはフィールド上のキャラクターの座標を更新する処理を行います。
座標を更新するキャラクタは一般に複数存在し、出現したり消えたりする可能性もあるでしょう。
これらの処理の実行管理は出来るだけ専用のクラスで行いたいものです。
間違ってもシナリオを作成する段階で意識すべきことではないでしょう。

このような処理は、大本のシステムにタスクを登録するようにすれば効率的でしょう。
たとえば、MotionTaskは以下のようになると思います。

かなり無理やりですが、タスクの登録/解除を行うRegister/Unregisterメソッドと登録されたタスクを実行するRunメソッドが出来ると思います。
実際の動きはUpdateCoodinateを継承したクラスにて実装します。
たとえば、直線の動きならLinearMotionクラスを、円運動ならCurveMotionクラスをUpdateCoodinateクラスから派生させます。

この考え方は、ゲームに限らずアプリの開発でもよく用いられています。
因みに、上の実装はC#ならdelegateを使えば非常に簡単に実装できます。
C#のdelegateとゲームのタスクシステムはなかなかに相性が良いです。

他のタスクも同様の設計をしていけばよいかと思います。

まとまりが悪くなってしまいましたが、タスクシステムのクラス設計についてのメモ書きでした。