fc2ブログ

Win32並行処理プログラミング入門

 昨今マルチコアCPUが普及し、並行処理が一般化しました。ですから、プログラマにとって並行処理プログラミングは必須知識だという事が出来ます。そこで、Win32並行処理プログラミングの解説を書く事にしました。
 先ずは、スレッドを使用したサンプルプログラムを見て下さい。

#include <iostream>
#include <windows.h>
#include <tchar.h>
#include <process.h>
using namespace std;

unsigned __stdcall ThreadFunc( void* pvParam ) 
{
    int value = PtrToInt( pvParam );
    cout << "スレッドに渡された値は" 
        << value << "です。" << endl;
    return 0;
}

int _tmain( int, _TCHAR* )
{
    int paramValue = 1000;
    HANDLE hThread = ( HANDLE ) _beginthreadex ( 
        __nullptr,
        0U,
        ThreadFunc,
        ( void * ) ( INT_PTR ) paramValue,
        0U,
        __nullptr );
    WaitForSingleObject( hThread, INFINITE );
    CloseHandle( hThread );
    return 0;
}

このサンプルプログラムの内容を簡潔に述べると、新しいスレッドを作成し、「パラメーターに指定された値を表示する関数」を実行させています
 細かい説明は長くなるので次回行います。続く...
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

意外と簡単な高階関数(C#編)

 命令型言語に慣れた方は、関数型言語を難しいと感じるようです。どこを難しいと感じるのかは人それぞれですが、関数をファーストオブジェクトと考えるところが一つの壁になっているようです。そこで今回は、関数型言語に慣れていないC#使いのために、高階関数の解説をします。
 高階関数を簡潔に言うと、関数を引数として受け取る関数や、関数を返す関数の事です。文章では分かり難いと思いますので、サンプルを示します。

using System;
using System.Collections.Generic;
class Higher_order_Function
{
    static void Main( string[ ] args )
    {
        //データを準備する
        Console.Write( "演算前の数値:" );
        List< int > list = new List< int >();
        for ( int i = 0 ; i < 10; i++) {
            list.Add(i);
            Console.Write( "{0} ", list[ i ] );
        }
        Console.WriteLine();

        //加算演算を適用して表示
        int value = 5;
        Console.WriteLine( "{0}を加算", value );
        Apply( list, ( x, y ) => x + y, value );
        Console.Write( "加算後の値:" );
        foreach(  int val in list ) {
            Console.Write( "{0} ", val );
        }
        Console.WriteLine( "\n" );

    }

    //数値リストに対して演算を適用する高階関数
    static void Apply( List< int > list ,
              Func< int, int, int > fun ,
              int value ) 
    {
        for ( int i = 0; i < list.Count; i++ ) {
            list[ i ] = fun( list[ i ], value );
        }
    }
}

このサンプルは、関数を引数として受け取る関数Applyを使用して、任意の演算を数値リストに対して適用しています。何の演算でも構わないのですが、このサンプルでは、整数値リストの全要素に対して加算演算を行っています。
 サンプルコードの緑色の部分に注目して下さい。高階関数のポイントがつかめます。.NETで関数を引数として受け取る関数を作成するには、デリゲートを使用します。呼び出す側は、ラムダ関数を使用します。ラムダ関数の使用は必須事項ではありません。複雑な関数を渡したい場合は、メソッドのポインターを指定しましょう。例えば、このサンプルでメソッドのポインターを指定する場合、加算を行う関数Addを定義してから 、 Apply( list, ( x, y ) => x + y, value );の部分をApply( list, Add, value );に変えます。
 高階関数を使用することのメリットは、定義する関数の数を減らし、アルゴリズムをより抽象的に捉える事が出来る事です。先ほどのサンプルを例に挙げると、これが良く分かると思います。もし高階関数を使用しなければ、加算・減算・乗算・除算・・・などの単純な関数を、何度もコーディングする作業が生じます。この作業は煩雑なだけで、何も良い事がありません。うっかりミスをしてしまうかもしれませんし、保守の負担が多くなります。また、仕様変更の際、変更漏れが生じるかもしれません。それにこの様な作業は、アルゴリズムの本質とは関係のない事です。
 なお、今回のサンプルでは、単純化する為に型を限定しましたが、実務ではジェネリックを併用しましょう。ジェネリックを併用する事により、さらに多くの場面で使用できる関数が定義できます。

//ジェネリックな高階関数(※オーバーフローとアンダーフローに注意)
static void Apply< T >( List< T > list, Func< T, T, T > fun, T value )
{
    for ( int i = 0; i < list.Count; i++ ) {
        list[ i ] = fun( list[ i ], value );
    }
}

 今回の記事を通じて、高階関数が意外と難しくない事が分かって頂けたと思います。利点が多く、簡単な高階関数を使わない手はありません。どんどん使用しましょう。生産性が確実にUPします。ただし、使い過ぎには注意して下さい。たとえ有益な機能であっても、使い過ぎは毒になります。

テーマ : プログラミング
ジャンル : コンピュータ

実践的オブジェクト指向分析入門

 プログラム言語に依存しない、オブジェクト指向の概念を正しく理解するには、オブジェクト指向分析を知らねばなりません。また、システムを正しく構築するには、オブジェクト指向分析を知る必要があります。そして、不景気を乗り切るには、開発者全員がオブジェクト指向分析を知り、高品質な製品を素早く作成する必要があります。そこで、この記事では、オブジェクト指向分析について解説します。
 オブジェクト指向分析を一言で表現すると、実世界のシステムをモデル化する事です。情報システムを構築するには、実世界の物事を段階的に抽象化し、情報処理機器で実現できるようにせねばなりません。これはシステムの規模とは関係ありません。アプリケーション、システムソフトウェア、中小企業のシステム、大企業のシステム・・・これら全ての情報処理製品に共通する事です。
 しかしながら、実のところオブジェクト指向分析は、一意に定まった概念ではありません。この世には、数多くのオブジェクト指向方法論が存在し、方法論ごとにオブジェクト指向分析の概念が異なります。そこでこの記事では、有力なオブジェクト指向方法論OMTに、私が実践で培った知識を加えた、実務で使えるオブジェクト指向分析を解説します。
 続く・・・

テーマ : ソフトウェア開発
ジャンル : コンピュータ

アジャイル開発と業務分析2

 この記事は、アジャイル開発と業務分析1の続きです。前回は業務分析の基礎を解説しましたので、今回は踏み込んだ内容を書きます。
 初期段階で行う業務分析は、オブジェクト指向分析の一部です。初めから完璧に分析する事を目指してはなりません。あくまでも、大まかな枠組みを把握するのが目的であって、細部に踏み込み過ぎてはならないのです。細部を分析しようとすると、色々な弊害が起きます。
 細部を分析することの弊害は、木を見て森を見ずになる事と、エンドユーザーに悪い印象を与える事です。細部に拘って、根本的な所で間違う人がいますが、システムは全体像を把握しないと構築できません。また、細かい事を根掘り葉掘り聞き過ぎると、エンドユーザーに不快感を与えます。業務を把握することも大事ですが、コミュニケーションの円滑化も重要な目的なので、その様な事態は絶対に避けましょう。アジャイル開発はウォーターフォール開発モデルではありません。オブジェクト指向分析も段階的に行います
 アジャイル開発の初心者は、オブジェクト指向分析を段階的に行う事に不安を感じます。しかしその不安は、オブジェクト指向分析を完璧にしても解消できません。それどころか、逆に悪化すると断言できます。何故ならば、システム開発に変化はつきものであり、完璧な分析は存在しないからです。この事実を言うと、エンドユーザーが要望を言えないのが原因だという人がいます。ですが、愚痴をこぼしたり、エンドユーザーを責めたりする前に、その変化の一部は、開発側が起こしているものだという事実を肝に銘じましょう。
 これは意外と知られていないのですが、開発側が仕様要求に変化をもたらしています。不思議だと感じるかもしれませんが、これはごくごく自然な現象です。我々はエンドユーザーの業務を効率化する為に、システムを提供しています。従って、業務そのものに変化が生じるのは当然だと言えるでしょう。変化を嫌がる人もいますが、変化をもたらさないシステムは、何の役にも立っていないという事を意味しています。よいシステムの提案ほど、エンドユーザーの業務に変化をもたらします。
 

テーマ : ソフトウェア開発
ジャンル : コンピュータ

C++/CLIのラムダ式に関する感想

 C++/CLIのラムダ式は、デリゲートに直接対応していません。それに加えて、マネージ型の変数をキャプチャ出来ません。その理由は、C++/CLIのラムダ式が値型だからです。他の理由もあるかもしれませんが、ひとまず私はそれが直接的な原因だと考えております。C#やVBのラムダ式は、デリゲートに対応していますが、その実態は、コンパイラが生成したメソッドです。.NETのメカニズムを考えれば、スタックに確保される値型がデリゲートに対応していないのは仕方がないと思います。
 C++/CLIのラムダ式が何故値型なのかについては、恐らくC++の関数ポインタの概念と関係していると思われます。C++/CLIは、マネージプログラミングとネイティブプログラミングの混合が想定されています。それを考慮すると、ラムダ式が値型なのは避けられないでしょう。
 しかしながら、将来もそうなるとは決まっていません。例えば、コンパイラオプションにclr:pureが指定されたら、C#とVB同様メソッドを自動生成するなどと言った対応が想像できます。私はC++/CLI開発チームの一員ではないので詳しい事情は分かりませんが、将来C++/CLIのラムダ式がデリゲート対応になるという希望は、あるのではないでしょうか?

注意:この記事は、私が過去にC++/CLIのラムダ式を独自調査した結果考えた事です。調査時間は10分ほどですし、私はC++/CLIの開発チームの一員ではないので、正しいという保証はどこにもありません。

テーマ : プログラミング
ジャンル : コンピュータ

アジャイル開発と業務分析1

 この記事は、アジャイル開発と業務分析の続きです。引き続き、アジャイル開発と業務分析の関係を述べていきます。
 業務分析で大事なのは、あくまでも業務の把握を目的とし、設計まで踏み込まないという点です。オブジェクト指向分析とオブジェクト指向設計を混同してはなりません。あくまでも、エンドユーザーの業務を把握する事が目的なのです。具体的には、年単位・月単位・週単位・日単位の業務の流れと、用語の理解および整理を行います。オブジェクト指向設計を混同すると、情報処理の世界と業務の世界が混合し、余計に業務が見えにくくなります。また、エンドレス設計になりがちです。
 年・月・週・日に分けて業務の流れを把握する理由は、大概の業務は単位ごとに、量と行う業務に変化が生じるからです。よくある間違いが、日単位で業務のヒアリングを行い、分かったつもりになる事です。エンドユーザーの業務も多面的であり、偶然ヒアリングをした前後の業務だけを調査しても、真に役に立つシステムにはなりません。それでは、最繁時にストップするようなシステムや、部分的にしか役立たないシステムが出来上がってしまいます。
 用語の理解と統合は、エンドユーザーと円滑にコミュニケーションを行う為に必要です。統合が必要な理由は、エンドユーザー側も、部門間で用語の使い方が異なる場合が多々あるからです。基幹業務システムを開発する際は、この点が非常に重要です。用語の不統一は、デーベースの設計に悪影響を与え、システムの品質を低下させます。また、コミュニケーションを阻害する大きな要因にもなります。
 業務分析は、エンドユーザー側の要求をくみ取る為のものだけではありません。開発サイドの用語や概念も、エンドユーザーに伝えるという重要な側面があります。日本でありがちなのは、お客様を神様扱いし、自分の考える事を伝えないのが原因で、コミュニケーションが上手く取れないという状況です。コミュニケーションは双方向なものであり、片方の要望を聞くだけで成り立つものではありません。一方通行にしてしまうと、所謂モンスタークレーマーが誕生します。昨今モンスタークレーマーが社会問題になっておりますが、日本のお客様は神様だという極端な商慣習が、その土壌を作っていると言えます。
 業務分析の重要な目的は、コミュニケーションの円滑化ですが、一つ注意するべき事を書きます。それは、公私混同する事がコミュニケーションではないという事です。日本でありがちなのは公私混同ですが、それは癒着を生みだします。例えば、一つの部門だけに便宜を図る、システムの機能を価格以上に盛り込む...などと言った出来事が発生します。こういうと、日本では冷徹なビジネスマンだと取られがちですが、それは極論です。人間の感情を無視しすぎるのは問題ですが、感情を優先させすぎるのもまた問題です。極端な姿勢を止め、一線を超えないようにしましょう。
 続く・・・

テーマ : ソフトウェア開発
ジャンル : コンピュータ

スレッド数決定問題11

 この記事はスレッド数決定問題10の続きです。引き続き、コーディング規約などの実装段階における、スレッド関連の問題を語ります。
 並列処理を実装するにあたって忘れてはならないのは、想定する処理時間はどれくらいなのかを明記する事です。明記しておかないと、不注意なプログラマが長時間を要する並列処理を、連続して呼び出してしまうかもしれません。そんな馬鹿な事をしないと、思われる方がいるかもしれません。ですが、コードは再利用されるので、実装の詳細を知らないプログラマが、コードを扱う可能性がありますし、並列処理を知らないプログラマも沢山います。さらに最悪な状況ですと、テストデータが不十分で潜在的なエラーが発現せず、本稼働した後に障害が発生する可能性すらあります。また、深刻な障害が起きずに、パフォーマンス劣化などの形で表れるかもしれません。こうした不都合は積み重なります。ある意味、システムが早期にストップするよりも性質が悪いエラーだと言えるかもしれません。それらの不都合を避けるために、およその処理時間をAPIドキュメントなどに明記しましょう。そうすれば、並列処理特有のエラーをある程度避けられます。
 今回はもうひとつ重要な事を挙げます。それは、オブジェクトの事前条件・事後条件・不変表明です。並列処理プログラミングを行っていても、非オブジェクト指向言語を使っていない限り、オブジェクト指向プログラミングの事も考慮せねばなりません。並列処理を行った場合、並列処理特有の条件がありうるので、十分な注意が必要です。表明を正しく行う事により、並列処理特有のエラーも減らせます。
 数回に渡って、実装段階の注意点を述べてきました。これらの事柄はスレッド数の決定に関連しています。何故ならば、オブジェクト指向設計を行った段階で、スレッド数を厳密に決定する事は不可能だからです。オブジェクト指向設計では、実装段階の事から切り離して考えます。しかし、並列処理は実装に依存する部分が多く、予め全てを予想する事は不可能に近い事です。単純なソフトウェアならば、プログラマが勝手にスレッドを使用しても問題ないかもしれませんが、システム規模になると、それでは問題が生じます。実装段階で判明した事を考慮しつつ、設計を微調整せねばなりません。
 続く・・・

テーマ : プログラミング
ジャンル : コンピュータ

意外と簡単な高階関数(VB.NET編)1

 先ずは意外と簡単な高階関数(VB.NET編)を読んで下さい。前回は関数を引数として受け取る関数を解説しましたので、今回は関数を返す関数を解説します。
 初めての人は難しく感じると思いますが、関数を返す関数は簡単な概念です。サンプルを見れば直ぐに分かると思います。

Module Module1

    Sub Main()

        Dim x As Integer = 10
        Dim y As Integer = 2

        '四則演算の結果を表示
        Console.WriteLine("{0} + {1} = {2}",
                          x, y, GetOperator("+")(x, y))
        Console.WriteLine("{0} - {1} = {2}",
                          x, y, GetOperator("-")(x, y))
        Console.WriteLine("{0} * {1} = {2}",
                          x, y, GetOperator("*")(x, y))
        Console.WriteLine("{0} / {1} = {2}",
                          x, y, GetOperator("/")(x, y))

    End Sub

    '演算を行う関数を返す関数
    Function GetOperator(ByVal ope As String) _
        As Func(Of Integer, Integer, Integer)

        Select Case ope
            Case "+"
                Return Function(x As Integer, y As Integer) (x + y)
            Case "-"
                Return Function(x As Integer, y As Integer) (x - y)
            Case "*"
                Return Function(x As Integer, y As Integer) (x * y)
            Case "/"
                Return Function(x As Integer, y As Integer) (x / y)
            Case Else
                Throw New ArgumentException(ope & "は無効です。")
        End Select

    End Function

End Module

このサンプルは、演算子を文字列として受け取り、適切な関数を返す高階関数を定義しています。そして、定義した高階関数(GetOperator)を使用し、演算結果を表示しています。
 ポイントは、Funcジェネリックデリゲートを使用している点と、ラムダ式を使用している点です。デリゲートとラムダ式を組み合わせるだけで高階関数が定義できます。使用法も実に簡単で、関数を呼び出すのと同様に指定できます。
 高階関数はプログラミングの幅を広げます。簡単で有益な高階関数を有効に活用しましょう。

テーマ : プログラミング
ジャンル : コンピュータ

アジャイル開発と業務分析

 専門書を片手にアジャイル開発を行おうとすると、高い確率で失敗します。その理由は様々で、組織の体質・契約形式・無理解・コミュニケーション不足...など多くの理由があります。今回はそのうちの一つである、契約直後に行うべき事について書きます。
 私がアジャイル開発を実践するにあたって、最初の段階で注意を払っているのが契約です。契約については、ある程度解説しましたので、次の段階へ移ります。
 契約が終わった後するべき事は、エンドユーザーの業務の分析です。システムを使用する会社は、業務を効率化する為に導入する筈です。従って、業務から乖離したシステムは不必要です。必要なシステムを提供するのが我々の仕事であり、構築するシステムは業務にあったものではなくてはなりません。むろん、契約前にある程度の事は把握しているでしょうが、それ程深く理解していないのが通常の状態です。業界知識だけでは不十分であり、システムを導入するエンドユーザーの業務を知る事から始めなくてはなりません。巷にあるアジャイル開発の専門書には、業務分析の事が書かれていませんが非常に重要です。ただし、重要だからと言って、既存のシステム開発と同様に分析段階を実施しても失敗します。契約と同様に、業務分析もアジャイル開発に適したものにしなくてはなりません。
 業務分析を行うタイミングは基本契約締結後です。基本契約を締結した後に直ぐ行動する事により、お客様から信頼して頂けるようにします。ここで注意しなくてはならないのは、分析を専任する人が業務分析を行っても無駄だという点です。ウォーターフォール開発モデルの発想で、分析者とお客様だけで会議をしてしまうと、そのプロジェクトは失敗します。何故ならば、関係者のコミュニケーションを円滑にし、現実から乖離したシステムにならないように、十分な工夫をせねばならないからです。開発工程に関わらない分析者と、エンドユーザーの代表者が話しをしても、開発作業に関する知識と経験が足りないので、現実に即したシステムが構築できません。また、実際に開発を行うチーム側も業務を知らねば、実際に役立つシステムが出来上がりません。知識の共有化が、開発を成功させるキーワードです。
 続く・・・

テーマ : ソフトウェア開発
ジャンル : コンピュータ

C++/CLIの事例から考える構文のあり方

 先日、久し振りにC++/CLIをやって、思い出したので書きます。C++/CLIは、Managed C++と比べて、非常に読みやすくなっています。ですがどうにもならない事もあります・・・

// Managed C++
public __gc __abstract class AbstractClass{ /*省略*/ };

// C++/CLI
public ref class AbstractClass abstract { /*省略*/ };

どこか違和感がありませんか?先に言っておきますが、C++/CLIとコメントが混じって見にくいとかはなしです。
 気付いたと思いますが、abstractキーワードの位置が違います。その理由は明記されていませんが、恐らく字句解析&構文解析と互換性がらみの問題が原因だと思います。
 ref classは2つで一つのキーワードです。refだけでは意味を持ちませんし、classだけだったらネイティブな型になってしまいます。という事は、字句解析&構文解析する時に、abstractが混じったら面倒だという想像がつきます。
 ref abstract class にされても嫌ですし、class abstract ref にされても嫌です。それに、一つのキーワード混入を許せば、「じゃあsealedもいいよな」、「virtualの位置もフリーでいいんじゃね?」などと多くの注文が発生しそうです。
 こうした事を色々考えるのが非常に面白いです。

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター