● 実行速度について - 乗除算を避ける・変更する

マルチスレッド

マルチプロセッサやマルチコアのCPUを使用しているマシンでは、複数のスレッドで平行して処理を行う事で、全体の速度効率を改善する事ができる場合があります。

マルチスレッド化する場合、通常はある程度纏まった処理で行いますが、fixed X では関数単位で行う事も考えられます。巨大な変数を計算する場合は、計算を別スレッドで行い、完了するまでの間は他の処理をメインスレッドで行ってしまいます。



この方法を行うには、並列計算が効率良く行える順序を考えなければなりません。
例.

#include <windows.h>
#include <process.h>
#include "fixedX.h"

typedef struct {
    PFIXEDVAL       px,py,prem;
    INT             width;
    INT             ret;
    HANDLE          hThread;
    UINT            uThreadID;
} DIV_PARAM,*PDIV_PARAM;

UINT __stdcall      div_thread(PDIV_PARAM prm)
{
    prm->ret = fixed_div(prm->px,prm->py,prm->prem,prm->width);
    return 0;
}

typedef UINT        (__stdcall *THREAD_ROUTINE)(LPVOID );

HANDLE      parallel_div(PDIV_PARAM prm)
{
    return (prm->hThread = (HANDLE )_beginthreadex(
        NULL,INIT_STACKSIZE,(THREAD_ROUTINE )div_thread,
        &prm,0,&prm->uThreadID));
}
この例は、除算だけを行うスレッドを作成するルーチンです。除算が必要な時に関数parallel_div を呼び出し、その後は除算結果が必要な処理が出現するまで、他の処理を行います。
    DIV_PARAM           d;

    d.px = x;
    d.py = y;
    d.prem = rem;
    d.width = width;

    if (!parallel_div(&d)){

        スレッドが作成できなかった場合

    }else{

        平行して行う処理

    }
除算結果が必要になった時は、DIV_PARAM構造体のメンバ px の指す領域を参照すれば良い訳ですが、その前にスレッドの完了を調べる必要があります。
    WaitForSignleObject(d.hThread,INFINITE);
    CloseHandle(d.hThread);
    if (!d.ret){

        除算エラー

    }else{

        1. 次の除算スレッド開始

        2. 前の除算結果を使った並行処理

    }
まだ計算中の場合は、完了するまで待機します(同期処理)。除算と平行して行う処理の時間が短い場合はこの段階で待つ事になりますが、スレッドの方が先に終了する事もあります(除数が 2n の場合や除算エラーの場合等)。
完了したら、スレッドのハンドルをクローズし、結果を参照・処理します。

上記の例はスレッドの生成・破棄がオーバーヘッドになるので、実際に使用するには、まだ洗練する必要があります。プログラム全体が実行中の時は除算スレッドが生存している様にし、Windows API の同期処理により除算の開始を制御する形にした方が良いでしょう。しかし、計算関数自体の処理時間が秒以上のオーダーになるような、非常に巨大な変数を扱う場合は、この形のまま使用しても一応の効果はあります。