fc2ブログ

アジャイル開発を元に考えるプロジェクトマネージャのあり方7

 この記事は、アジャイル開発を元に考えるプロジェクトマネージャのあり方6の続きです。前回はデスマーチの原因について述べ、その解決方法を示しました。今回はマネージャが行うべき事を解説します。
 プロジェクトマネージャが行うべき事を2つ挙げると、現実を受け止めて素直に行動する事と、職場の環境に気を配る事です。実に残念な事ですが、多くの日本企業はプロジェクトマネージャとなった人間の役割を固定し、最新技術に触れる機会を遠ざけてしまいます。ですから、プロジェクトマネージャになった人間は、たいてい情報処理技術の変化についていけません。少しの間ならば抵抗する事も出来るでしょうが、不合理な職場環境下では忙殺されて、徐々に変化についていけなくなります。ですから、その様な不合理な環境下に置かれたプロジェクトマネージャは現実を受け止め、自分が技術に疎い事を受け入れなくてはなりません。情報処理技術に疎くなる事を避けるには、情報処理技術の本質を熟知して不合理な事をしない企業へ転職するか、技術力を高め続ける為に独立するしかありません。
 プロジェクトマネージャとして一番してはならない事は、現実を受け止めず、かといって行動もせず、ただ開発メンバーに自分の時代遅れのやり方を強要する事です。例えば、オブジェクト指向を使わせない、SQLを使わせない、並行処理を否定する、自分が知らない事を否定する、開発メンバーが学習する事を妨害する、自分が知らない技術が採用する事を妨害する...等と言った事があります。この様な不合理な行動は、開発メンバーの作業効率を下げるだけの生産妨害行為です。プロジェクトマネージメントは開発作業の生産性を上げるのが使命です。逆の行為をするのであればプロジェクトマネージャ失格だというほかありません。
 この記事を読んだ人は恐らく「自分はそんな愚かな行為をしない」と考えるでしょう。しかしながら、生産行為を妨害している張本人は自覚していません。情報処理技術の変化の速さを受け止めない人間は、いつの間にか非生産的な人間になっています。こうなってしまってからでは遅いので、常に情報処理技術の変化を意識しなくてはなりません。情報処理技術の変化の速さを常に意識し、他の開発メンバーの助言を素直に聞く姿勢が大事です。これは技術者以前に人として大切な事です。謙虚さを忘れてはなりません。
 繰り返しになりますが、システム開発において重要な経営資源は「人」です。開発メンバーが仕事に集中できるように気を配りましょう。具体的には、低スペックのPCでプログラミングさせない、他の開発メンバーを不快にさせる人は直ぐに注意する、衛生面に気を付ける、クリップボードを用意する、仕様を理解していない人に教える、開発に必要となる技術を習得していない人を訓練する・・・などといった行為を行う事により仕事環境を整え、人間の生産能力を最大限まで引き出します。日本の企業では根性論が多く、人の感情を無視する事を合理的だという人が沢山います。しかしながら、合理的に考えると全ての人間は感情を持ち、感情により生産能力が上下します。システム開発で必要な物の価格はたかが知れています。人件費が一番高くつくので人を一番大切にしましょう。優秀な技術者はそうでない技術者に比べて100倍の生産能力を持つ事を忘れてはなりません。真に合理的に考えるならば、システム開発では人を一番大切に扱うべきなのです。続く...
スポンサーサイト



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

アジャイル開発を元に考えるプロジェクトマネージャのあり方6

 この記事は、アジャイル開発を元に考えるプロジェクトマネージャのあり方5の続きです。前回プロジェクトマネージャの存在価値は高いものの、プロジェクトマネージャが情報の流れを適切にコントロール出来ない場合、プロジェクトはデスマーチになる事を解説しました。今回はその原因を解説します。
 この問題を理解するには、システム開発がどのような情報を必要とするのかを把握せねばなりません。システム開発に必要な情報は様々ですが一例をあげると、納期、概要モデル(現実をモデル化したもの)、分析モデル、設計モデル、その他細かい仕様、プロジェクトの目標、情報処理技術の選択肢、テクニック、既存のバグ...などです。それらの情報がプロジェクトメンバーに行き届いていないとデスマーチになります。
 これらの情報の中で日本の企業で不足しがちなのが、情報処理技術に関する情報です。日本の企業は職位と役割を混同しており、プロジェクトマネージャ=偉い=年配の人だと考え、役割が違う職業を職位が低いと見做しています。その結果、プロジェクトマネージャになった途端技術力が下がり、仕事の内容を把握していないプロジェクトマネージャが誕生します。この問題の本質は、人の評価をおざなりにした点と、情報処理技術の性質を無視した点にあります
 情報処理技術は変化が速く毎日進歩しています。ですから、たとえ優秀なシステムエンジニアであっても、その人をプロジェクトマネージャに任命し他の役割の仕事をさせない時点で、情報処理技術に関する情報が適切にコントロールできなくなります。残念ながら情報がコントロールできないのであれば、プロジェクトマネージャの存在価値はなくなります。そもそも日本企業が職位を定めるのは、年功序列を前提とした給与体系を体現する為です。年功序列を維持できない事は明白です。情報処理技術の性質と相いれないその考えを改めなくてはなりません。
 ではどのようにすればいいのかと言いますと、固定した職位ではなく職能で給与を決定し、プロジェクトマネージャを交代制にすれば良いのです。プロジェクトマネージャを交代制にすれば情報処理技術の変化に対応できます。むろんプロジェクトマネージャを任せる人は、プロジェクトマネージメントを学習しなければなりません。この方法は人の評価を熟考しなくてはなりませんが、そもそも人の評価をおざなりにして企業の発展はありえません。情報処理技術の性質を加味した、変化に強い評価方法を考え出さなくてはなりません。この話題も奥が深く面白いのですが、プロジェクトマネージメントの話しから脱線しますのでこの連載では深入りしません。
 話しをプロジェクトマネージメントに戻します。不幸にも不合理な企業体質の下で仕事をする事になったプロジェクトマネージャがするべき事は、現実を受け止めて素直に行動する事と、職場の環境に気を配る事です。続く...

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

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

 この記事は、Win32並行処理プログラミング入門30の続きです。前回はスレッドセーフとcoutについて書きました。今回はcoutを勧めない理由を詳しく書きます。
 繰り返しになりますが、coutの様な副作用を伴うグローバルオブジェクトを、並行処理する事はお勧めできません。文章だけだと分かり難いと思いますので、サンプルを挙げてその理由を解説します。

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

//インスタンスのポインタを保持するクラス
class InstanceAndParameter
{
private:
    void* ins;
    void* param;
public:
    InstanceAndParameter( void* ins, void* param ) 
        : ins( ins ), param( param ){}
    void* getInstance() const { return ins; } 
    void* getParameter() const { return param; }
};

//並行的にコンソールへスレッドIDを表示するクラス
class ConcurrentPrint
{
private:
    LPCRITICAL_SECTION _coutsection;
public:
    ConcurrentPrint( LPCRITICAL_SECTION coutsection )
        : _coutsection( coutsection ) {}

    //スレッドから呼び出されるメソッド
    static unsigned __stdcall CallPrintFunc( void* pvParam )
    {
        //パラメータのチェック
        _ASSERTE( FALSE == IsBadReadPtr( pvParam, 
                sizeof( InstanceAndParameter ) ) 
            && "スレッドに渡されたパラメータが無効です" ); 

        //インスタンスとパラメータを取り出してメソッドを実行
        InstanceAndParameter* ip = 
            reinterpret_cast< InstanceAndParameter* >( pvParam );
        ConcurrentPrint* obj = 
            reinterpret_cast< ConcurrentPrint* >( ip->getInstance() );
        obj->PrintID();
        return 0;
    };

    //スレッドIDを表示する
    void PrintID() 
    {
        EnterCriticalSection( _coutsection );
        cout << "スレッドID【" 
            << GetCurrentThreadId() << "】" << endl;
        LeaveCriticalSection( _coutsection );
    }

    /* クリティカルセクションを勝手に削除してはならない
    ~ConcurrentPrint()
    {
        DeleteCriticalSection( _coutsection );
    }
    */
    
};

//並行的にコンソールへ「ピヨ」を表示するクラス
class ConcurrentPiyo
{
private:
    LPCRITICAL_SECTION _coutsection;
public:
    ConcurrentPiyo( LPCRITICAL_SECTION coutsection )
        : _coutsection( coutsection ) {}

    //スレッドから呼び出されるメソッド
    static unsigned __stdcall CallPiyoFunc( void* pvParam )
    {
        //パラメータのチェック
        _ASSERTE( FALSE == IsBadReadPtr( pvParam, 
                sizeof( InstanceAndParameter ) ) 
            && "スレッドに渡されたパラメータが無効です" ); 

        //インスタンスとパラメータを取り出してメソッドを実行
        InstanceAndParameter* ip = 
            reinterpret_cast< InstanceAndParameter* >( pvParam );
        ConcurrentPiyo* obj = 
            reinterpret_cast< ConcurrentPiyo* >( ip->getInstance() );
        int count = 
            PtrToInt( reinterpret_cast< INT_PTR >( ip->getParameter() ) );
        obj->Piyo( count );
        return 0;
    };

    //スレッドIDを表示する
    void Piyo( const int count ) 
    {
        EnterCriticalSection( _coutsection );
        for ( int i = 0; i < count; i++ ) {
            cout << "ピヨ";
        }
        cout << endl;
        LeaveCriticalSection( _coutsection );
    }
};

int _tmain( int, _TCHAR* )
{
    //スレッド数の判定
    const int piyoCount = 2;
    const int printCount = 2;
    const int threadCount = printCount + piyoCount;
    if ( threadCount > MAXIMUM_WAIT_OBJECTS ) {
        cout << "【エラー】" << endl;
        cout << "指定するスレッド数が多すぎます。" << endl;
        cout << "指定するスレッド数は" 
            << MAXIMUM_WAIT_OBJECTS 
            << "以下にして下さい。" << endl;
        return -1;
    }

    //クリティカルセクションの準備
    CRITICAL_SECTION coutsection;
    InitializeCriticalSection( &coutsection ); 

    //各種スレッドを実行
    cout << "【各種メッセージを表示します】" << endl;
    HANDLE hThreads[ threadCount ];
    for ( int i = 0; i < printCount; i++ ) {

        //スレッドのパラメータを用意する
        ConcurrentPrint cprint( &coutsection );
        InstanceAndParameter threadparam( 
            reinterpret_cast< void * >( &cprint ), 
            reinterpret_cast< void * >( ( INT_PTR ) 0 ) );

        //スレッドを準備
        hThreads[ i ] = ( HANDLE ) _beginthreadex ( 
            __nullptr,
            0U,
            ConcurrentPrint::CallPrintFunc,
            reinterpret_cast< void * >( &threadparam ),
            CREATE_SUSPENDED, //直ぐには実行しない
            __nullptr );
    }
    const int piyoNumber = 10;
    for ( int i = printCount; i < threadCount; i++ ) {

        //スレッドのパラメータを用意する
        ConcurrentPiyo piyo( &coutsection );
        InstanceAndParameter threadparam( 
            reinterpret_cast< void * >( &piyo ), 
            reinterpret_cast< void * >( ( INT_PTR ) piyoNumber ) );

        //スレッドを準備
        hThreads[ i ] = ( HANDLE ) _beginthreadex ( 
            __nullptr,
            0U,
            ConcurrentPiyo::CallPiyoFunc,
            reinterpret_cast< void * >( &threadparam ),
            CREATE_SUSPENDED, //直ぐには実行しない
            __nullptr );
    }
    for ( int i = 0; i < threadCount; i++) {
        ResumeThread( hThreads[ i ] );
    }

    //タイムアウト時間をミリ単位で指定
    //※指定した時間は正確ではありません
    DWORD result = WaitForMultipleObjects( 
        threadCount, hThreads, TRUE, 2000 );

    //WaitForSingleObject関数が終了した原因
    cout << endl << endl;
    cout << "【スレッドの状態を表示します】" << endl;
    unsigned int max = ( WAIT_OBJECT_0 + threadCount - 1 );
    if ( result == WAIT_FAILED ) { 
        //エラーを表示する
        LPVOID title = _T( "エラー" );
        LPVOID msg;
        FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
            __nullptr,
            GetLastError(),
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 
            reinterpret_cast< LPTSTR >( &msg ),
            0,
            __nullptr
        );
        MessageBox( __nullptr, 
            reinterpret_cast< LPCTSTR >( msg ) , 
            reinterpret_cast< LPCTSTR >( title ), 
            MB_OK | MB_ICONERROR );
        LocalFree( msg );
        return -1;
    } 
    if ( result == WAIT_TIMEOUT ) {
        cout << "タイムアウトしてしまいました。" << endl;
    } else if ( ( result >= WAIT_OBJECT_0 ) & ( result < max ) ) {
        cout << "全スレッドの処理が終わりました。" << endl;
    } 
    cout << endl;

    //クリティカルセクションを削除
    DeleteCriticalSection( &coutsection );

    //ハンドルを閉じる
    for ( int i = 0; i < threadCount; i++ ) {
        CloseHandle( hThreads[ i ] );
        hThreads[ i ] = __nullptr; //念のためNULLに設定
    }

    cout << endl;
    return 0;
}

少し長いサンプルですがやっている事は非常に単純です。コンソールにスレッドIDとピヨを並行的に表示しているだけです。しかし問題点がいくつもあります。
 第1の問題は、クラスの仕様が多くなる事です。このサンプルでは、「必ずcout用のクリティカルセクションを持たねばならない」という仕様、「クリティカルセクションを勝手に削除してはならない」という仕様、「適切にクリティカルセクション操作用関数を使用せねばならない」という仕様の計3つの仕様が必要になります。何故ならば、cout用のクリティカルセクションを持たねばコンソール上の文字列は滅茶苦茶になり、勝手にクリティカルセクションを削除するインスタンスが存在すると、並行処理中の他のインスタンスが正常に処理を継続できなくなるからです。守るべき仕様が多いクラスは、再利用性が低くテストも行い難くなります。守るべき仕様が多いクラスを設計してはなりません。
 第2の問題は、利用する側も条件を守る必要がある事です。このサンプルでは、利用側のmain関数内でクリティカルセクションの初期化と削除が必要となります。200行程度の短いプログラムならばあまり問題になりませんが、実務レベルでは数十万行以上のプログラムを分割して複数のプログラマが担当します。複数のプログラマが守るべき条件が多くなるにつれて、作業効率が下がりバグの発生率が高くなります。従って、クラスを使用する条件を設ける事を極力避けるべきです。
 第3の問題は変更がやり難い事です。グローバルオブジェクトを共有すると、クラス間の結合度が高まり、仕様変更の影響範囲が広くなってしまいます。例えば、同期方式を変更する場合、ある前提の下にグローバルオブジェクトを使用しているクラスを全て見直さなければなりません。そうしないと、並行処理特有のバグが発生する可能性が十分にあります。実務では先を見据えてプログラミングせねばなりません。
 第4の問題は、そもそも並行処理する必然性がない事です。例えば、今回のサンプルで並行的にコンソール上に文字を表示する必然性があるのでしょうか?そんな事をせずに値を返すようにしておけば、後でその文字列を直列的にコンソールへ出力できます。そして、後で仕様が変更されファイルへ出力する事になっても直ぐに対応できます。
 以上のように、グローバルオブジェクトを用いた並行処理は問題が沢山存在します。問題が多い方式を積極的に採用する愚を犯さないように、グローバルオブジェクトを極力避けましょう。続く...

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

アジャイル開発を元に考えるプロジェクトマネージャのあり方5

 この記事は、アジャイル開発を元に考えるプロジェクトマネージャのあり方4の続きです。前回は、アジャイル開発と従来のプロジェクトマネージメント技法の対比により、問題を深く掘り下げました。今回も引き続き問題点を掘り下げつつ、新しいプロジェクトマネージメントについて記述します。
 新しいプロジェクトマネージメント手法である、能動的なプロジェクトマネージメントは難しい概念であり、直ぐには分からないと思います。理解するには従来の受動的なプロジェクトマネージメント技法とプロジェクトマネージメントの本質を知らねばなりません。先ずは、プロジェクトマネージメントの存在意義から解説します。
 古い時代のシステム開発は、少数精鋭で行う職人の仕事でした。しかし、システム規模の拡大とシステムの複雑化に伴い、少数精鋭では目的を達成できなくなり開発関係者の人数が増加しました。しかしながら人数が増加すると、コミュニケーションコストの増加により新しい問題が生じました。この問題については、プロセスマネージメントの領域ですので、プロセスマネージメントの理論を参照しつつ解説を進めます。
 プロセスマネージメントの理論によると、コミュニケーションの接点はn * ( n - 1 )が必要になると言われています(nはインタフェースの数)例えば、n = 10 (10人がバラバラに活動)だと、10 * ( 10 - 1 ) = 90ものコミュニケーションの接点が生じます。コミュニケーションの接点が多くなればなるほどコストが増加します。そして、コミュニケーションコストの増加に比例し個人の負担が増加します。そうなれば個人の生産力は下がり、開発グループ全体の生産性も下がります。生産性が下がるならばそもそも開発グループを組む意味がありませんが、少人数では目的が達成出来ません。従って、開発人数は増やし、コミュニケーションの接点は減らす必要があります。それを解決するのがプロジェクトマネージャであり、そこにプロジェクトマネージャの存在意義があります。
 この問題の原因は、インタフェースの数が多すぎる点にあります。ですから、プロジェクトマネージャが、共通インタフェースの役割を果たせば問題は解決します。プロジェクトマネージャが人を束ね、共通インタフェースの役割を果たすと、プロジェクトマネージャと開発者の関係に収束出来るので2nの接点しか要らなくなります。先ほどの例を挙げますと、2 * 10 = 20となります。この結果を見れば、プロジェクトマネージャの存在価値が分かると思います。
 これで話しが終わればよいのですが、残念ながら現実は計算式どおりになりません。プロセスマネージメントの効果があるのは、プロジェクトマネージャが正しく情報の流れをコントロールした場合だけです。それが出来ない場合、誤情報により開発グループは悲惨な状態に追い込まれます。この状態があの悪名高きデスマーチです。続く...

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

書籍をつつく145-プログラミング .NET Framework 第3版。序文すら面白い文句なしのバイブル。

みんな、.NETプログラミングやっているかい?♪久しぶりの書籍レビューピヨ♪
この本は凄く有名な本で、文句なしのバイブルピヨ。読んでいないWin系開発者はモグリだとボクは思うな。



ボクは.NET1.0が出た時から実務で.NETを使用しているから、この本は第1版から読んでいるピヨ。それを踏まえての感想なんだけど、これほど.NETプログラミングで必要だと思う本はないピヨ。 .NETプログラミングをする際に、1冊だけ選べと言われたらこの本を選ぶピヨッ♪ アマチュアの人も是非読んでほしいピヨ。この本を読めば、.NETプログラミングの王道が見えるピヨ。

ところで、古くからの.NETプログラマが気になるのは、「何の記述が増えたか」だよね。
それについては、期待通りピヨ。ボクが望んでいた事が叶って嬉しいピヨ♪
増えた記述は、dynamic型・コードコントラクト・拡張メソッド・ラムダ式・名前付きパラメータ・省略可能パラメータ・並列処理(1部ぶん増えている!)ピヨ♪ピヨ♪ピヨ♪
並行処理に1部の分量書いている事に要注意。並列処理はやはり大事ピヨ。この本を道標にして、並行プログラミングの世界へ旅立とう!並行処理を実務で扱うとなると、並行アルゴリズムや並行システムの設計について書いていないから、これでもまだ足りないと思うけど、凄くいい出発点になると思うピヨ。足りない分は他の並行処理本と併読すればいいピヨ。
真面目な部分に加えて、Jeffreyの奥様が書いた序文が面白すぎるピヨ♪こういう部分まで面白なんて凄い良本ピヨ。
邦書もこれぐらい技術的にもそれ以外でも面白い本が出版されるといいな。ここ最近の邦書で技術的に面白いのは、ガベージコレクションのアルゴリズムと実装ぐらいかな?日本の出版業界も頑張ってほしいピヨ。買う本がなくてつまらないピヨぉ。
なにはともあれ、.NETを扱う人は絶対に読むべし!


他の本のレビューも読みたいピヨな人は書籍レビュー目次をチェックしてね♪

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

アジャイル開発を元に考えるプロジェクトマネージャのあり方4

 この記事は、アジャイル開発を元に考えるプロジェクトマネージャのあり方3の続きです。前回は、従来のプロジェクトマネージャの考え方について書く事により、問題点を明確にしました。今回は、アジャイル開発と従来のプロジェクトマネージメント技法の対比により、問題を深く掘り下げていきます。
 ウォターフォール開発モデルで培った従来のプロジェクトマネージメント技法は、納期・工程・人数だけに注目したものでした。しかしアジャイル開発が示す様に、あらかじめ仕様を確定しその通り工程を進める事は不可能です。その様に計画通りに進む事を前提とする考えは机上の空論です。
 システム開発に携わった人は知っていると思いますが、システム開発は計画通りに進みません。仕様そのものが常に変化しますので、「計画通り」という言葉は神様だけが口に出来ます。仕様が変化するのは当然の理です。役に立たない死んだシステムでなく、実際に役に立つ、生きているシステムを開発するのですから、常に変化に対処し続けねばなりません。ですから、従来の受動的な進歩管理型マネージメント技法は残念ながら通用しません。悲しい事ですが、現実からは逃げられません。変化に対処し続ける能動的なプロジェクトマネージメントを行わなくてはなりません。
 私がいう所の能動的なプロジェクトマネージメントとは、重要な経営資源である人と情報を活かすべく、情報の流れを円滑化させつつ人の生産力を最大限に向上させる事です。これは非常に難しい事ですが、元々システム開発は複雑なものです。しかしながら、今までその複雑さを直視していなかっただけなので、やるべき事をやるだけだと言えます。続く...

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

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

 この記事は、Win32並行処理プログラミング入門29の続きです。今回も引き続き、スレッドセーフについて解説します。
 前回の記事を読めば、スレッドセーフがなんとなくわかると思います。ですが、なんとなくでは実務で通用しないのでより正確に解説します。
 スレッドセーフとは、呼び出し側が同期オブジェクトなどを使用しなくとも、複数のスレッドから如何なる順序でアクセスされても正しく処理される状態の事です。つまり、スレッドセーフとは、呼び出し側が特別な工夫をせずとも複数のスレッドで使用できるという状態を指します。
 分かり難いと思いますので、具体例として前回のサンプルを用いて説明します。クリティカルセクション使用前のThreadFunc関数は、スレッドセーフでないcoutを使用しており、複数のスレッドから実行された時に表示がおかしくなりました。これでは「正しい」とは言えませんので、ThreadFunc関数はスレッドセーフではありません。一方クリティカルセクション使用後のThreadFunc関数は、複数のスレッドから実行されても表示が乱れないので「スレッドセーフな関数」です。
 ここでいう「正しさ」とは、不変表明と事後条件が守られる事です。なお、不変表明とは、常に守られる条件の事であり、事後条件とは実行後に規定の条件を満たす事です。
 再び前回のサンプルを持ち出して説明すると、ThreadFunc関数の不変表明は「宣言した全ての変数が変化しない」、事後条件は「コンソール画面上で、一行ごとに一つのスレッドIDを表示する」です。クリティカルセクション使用後のThreadFunc関数は、実行前も実行後も変数が変化しないので不変表明を満たし、一行ごとにスレッドIDが表示されるので事後条件も満たしています。また、呼び出し側であるmain関数は、同期用の関数(EnterCriticalSectionなど)を使用しておらず、スレッドの実行順序にも依存しないのでThreadFunc関数はスレッドセーフだと言えます。
 ただし、main関数内でクリティカルセクションオブジェクトの初期化と開放を行っているので、完璧なスレッドセーフではないと解釈する余地があります。クリティカルセクションオブジェクトの操作部分を隠蔽する為に、クラス設計を工夫する必要性があります。また、後で同期方法を変更する場合、複数のクラスを変更する羽目になる可能性があります。しかしながら、いくら努力してもcoutそのものが副作用を伴うグローバルオブジェクトなので、完璧なスレッドセーフだと言いきれない部分が残るでしょう。それに加え、そもそも並列的にコンソールへ出力しなければならない理由がないと思います。余計な作業が発生しないように、並行的にcoutを扱わない事をお勧めします。続く...

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

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

 この記事は、Win32並行処理プログラミング入門28の続きです。前回は、スレッドそのものについて解説しました。今回は、スレッドセーフについて解説します。
 Win32並行処理プログラミング入門25で提示したサンプル内で、coutはスレッドセーフでないと記述しました。

//※サンプルから抜粋
unsigned __stdcall ThreadFunc( void* pvParam ) 
{
    cout << "スレッドID【" 
        << GetCurrentThreadId() << "】" << endl;
    return 0;
}

スレッドセーフでなければどのような事が起きるのかは、サンプルを何回か実行すれば体験できます。では、スレッドセーフとはどんな状態なのでしょうか?
 それについては、クリティカルセクションを使用すれば体験できます。

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

CRITICAL_SECTION coutsection;
const int threadCount = 2;
unsigned __stdcall ThreadFunc( void* pvParam ) 
{
    EnterCriticalSection( &coutsection );
    cout << "スレッドID【" 
        << GetCurrentThreadId() << "】" << endl;
    LeaveCriticalSection( &coutsection );
    return 0;
}

int _tmain( int, _TCHAR* )
{
    //スレッド数の判定
    if ( threadCount > MAXIMUM_WAIT_OBJECTS ) {
        cout << "【エラー】" << endl;
        cout << "指定するスレッド数が多すぎます。" << endl;
        cout << "指定するスレッド数は" 
            << MAXIMUM_WAIT_OBJECTS 
            << "以下にして下さい。" << endl;
        return -1;
    }

    //クリティカルセクションを初期化
    InitializeCriticalSection( &coutsection );

    //スレッド開始
    HANDLE hThreads[ threadCount ];
    for ( int i = 0; i < threadCount; i++ ) {
        hThreads[ i ] = ( HANDLE ) _beginthreadex ( 
            __nullptr,
            0U,
            ThreadFunc,
            __nullptr,
            0U,
            __nullptr );
    }

    //タイムアウト時間をミリ単位で指定
    //※指定した時間は正確ではありません
    DWORD result = WaitForMultipleObjects( 
        threadCount, hThreads, TRUE, 2000 );

    //WaitForSingleObject関数が終了した原因
    cout << "【スレッドの状態を表示します】" << endl;
    unsigned int max = ( WAIT_OBJECT_0 + threadCount - 1 );
    if ( result == WAIT_FAILED ) { 
        //エラーを表示する
        LPVOID title = _T( "エラー" );
        LPVOID msg;
        FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
            __nullptr,
            GetLastError(),
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // 既定の言語
            reinterpret_cast< LPTSTR >( &msg ),
            0,
            __nullptr
        );
        MessageBox( __nullptr, 
            reinterpret_cast< LPCTSTR >( msg ) , 
            reinterpret_cast< LPCTSTR >( title ), 
            MB_OK | MB_ICONERROR );
        LocalFree( msg );
        return -1;
    } 
    if ( result == WAIT_TIMEOUT ) {
        cout << "タイムアウトしてしまいました。" << endl;
    } else if ( ( result >= WAIT_OBJECT_0 ) & ( result < max ) ) {
        cout << "全スレッドの処理が終わりました。" << endl;
    } 
    cout << endl;

    //クリティカルセクションを破棄
    DeleteCriticalSection( &coutsection );

    //ハンドルを閉じる
    for ( int i = 0; i < threadCount; i++ ) 
        CloseHandle( hThreads[ i ] );

    cout << endl;
    return 0;
}

このサンプルを実行すれば、スレッドセーフを感じられると思います。詳しい説明は次回します。

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

アジャイル開発を元に考えるプロジェクトマネージャのあり方3

 この記事は、アジャイル開発を元に考えるプロジェクトマネージャのあり方2の続きです。前回から引き続き、従来のプロジェクトマネージャの考え方について書く事により、問題点を明確にしていきます。
 前回述べたように、組織の人事制度が間違っている上に、プロジェクトマネージメントの手法そのものが間違っています。既存のプロジェクトマネージメント技法は、金・物・時間ばかりを意識し、情報と人をないがしろにしています。開発者ならば全員知っていると思うのですが、システム開発で重視するべきなのは人と情報です。人と情報がシステム開発に与える影響力は大きく、システム開発ほど人と情報が成否を分ける仕事は、存在しないと言えるほどです。
 システム開発に於いて人は大変重要です。優秀な開発者は、そうでない開発者の100倍の生産力を持ちます。それに加え、優秀な開発者は不可能を可能にします。また、システム開発は情報を扱うものなので、情報が重要なのは当然だと言えるでしょう。システム開発もまた情報処理です。情報そのものが不足していれば処理できません。
 それにも関わらず、残念ながら日本のIT産業は人と情報を軽視しています。重要な経営資源を軽視しているのですから、その結果は言うまでもないでしょう。従来のプロジェクトマネージメント手法が、重要な経営資源を有効に扱おうとしないのでシステム開発は失敗して当然だと言えます。表面的には成功しているように見えますが、それは表面的な事を取り繕って、失敗を直視していないだけです。日本のIT業界が成功していると考えている業界人は稀です。無理は長続きしません。近い将来、破綻が誰の目にも明らかになるでしょう。

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

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

 この記事は、Win32並行処理プログラミング入門27の続きです。前回から引き続きスレッドの解説を行います。
 前回述べたように、スレッドにはOSが管理する為の情報も含まれています。Windowsのスレッドに関する情報は、エグゼキュティブスレッド(ETHREAD)ブロック内にあります。その中で、OSが必要とする情報は様々です。例えば、スレッドが属するプロセスのID、スレッドの時間、セキュリティに関する情報(アクセストークンなど)、LPC(ローカルプロシージャコール)に関する情報、I/Oに関する情報、スレッドが所持するミュータントオブジェクトのリスト、待機に関する情報などがあります。多すぎると感じた人が居るかもしれませんが、これはWindowsに限った話しではありません。OSはスレッドに関する情報を沢山必要としています。
 幸い普通のソフトウェアをプログラミングする上では、大半の情報を意識する必要はありません。開発者が意識するべき事は、スレッドのスケジューリングに関する事柄です。スレッドスケジューリングについては、次回以降解説します。

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

プロフィール

インドリ

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カウンター