この前のグレースケール処理 マルチスレッド化してみた

Core2Quadで、実験したマルチスレッドグレースケール処理の記事を掲載しました
こちらをご覧ください



前回、グレースケール処理でInt* Byte*、どっちの処理が速いか?ってことを、
テストしてみたけど、あまり、速度上がらず…(´・ω・`)

激怒しちゃったんで、このグレースケール処理、マルチスレッド化してみた(w

いつものように条件は以下のとおり

CPU : AMD Athlon64x2 3800+(2.0GHz)
Memory : 1GB
OS : Windows XP Pro
言語: Visual Studio 2005(C#2.0) + .Net FrameWork2.0

画像データ1000回の
グレースケール処理を実行
リリースコンパイル
640 * 480
24ビットピクセル

1スレッド
11,703ミリ秒
640 * 480
24ビットピクセル

2スレッド
7,843ミリ秒
640 * 480
24ビットピクセル

4スレッド
7,390ミリ秒

う~む、余は満足じゃ!

それにしても、4コアで試してみたいなぁ。。。
もうちょっとしたら、4コアに変えるんで、そのとき再度、性能評価やってみよう…


コードは、4スレッド版です

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Threading;


namespace GrayScaleTest
{
public partial class Form1 : Form
{
private const int THREADCOUNT = 5;
static public Form1 m_MyObj; //スレッドへ情報を渡すため、自分自身のインスタンスをセット
private Bitmap m_ImageBackup; // 一時データ
private Bitmap m_bmapIn; // 入力データ
private Bitmap m_bmapOut; // 出力データ
private bool m_ThreadOnFL;
private bool[] m_ThreadJobFL;
private bool[] m_ThreadJobFixFL;
private Thread[] m_Thread;
private IntPtr m_SouPT;
private IntPtr m_DesPT;
private int m_Width; // Image サイズ
private int m_Height; // Image サイズ

public Form1()
{
InitializeComponent();
m_MyObj = this;
}

private void Form1_Load(object sender, EventArgs e)
{

pictureBox1.Image = null;
m_ThreadOnFL = true;
m_ThreadJobFL = new bool[THREADCOUNT];
m_ThreadJobFixFL = new bool[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i++)
{
m_ThreadJobFL[i] = false;
m_ThreadJobFixFL[i] = false;
}


m_Thread = new Thread[THREADCOUNT];

m_Thread[0] = new Thread(new ThreadStart(ThreadMethod0));
m_Thread[1] = new Thread(new ThreadStart(ThreadMethod1));
m_Thread[2] = new Thread(new ThreadStart(ThreadMethod2));
m_Thread[3] = new Thread(new ThreadStart(ThreadMethod3));
m_Thread[4] = new Thread(new ThreadStart(ThreadMethod4));
m_Thread[0].Name = "画像処理スレッド0";
m_Thread[1].Name = "画像処理スレッド1";
m_Thread[2].Name = "画像処理スレッド2";
m_Thread[3].Name = "画像処理スレッド3";
m_Thread[4].Name = "画像処理スレッド4";

m_Thread[0].Start();
m_Thread[1].Start();
m_Thread[2].Start();
m_Thread[3].Start();
m_Thread[4].Start();

}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
m_ThreadOnFL = false;
for(int i = 0; i < 200; i++)
{
Application.DoEvents();
Thread.Sleep(1);
}
}

private void button1_Click(object sender, EventArgs e)
{
string FileName;
if (openFileDialog1.ShowDialog() != DialogResult.OK)
{
return;
}
FileName = openFileDialog1.FileName;
m_ImageBackup = new Bitmap(FileName);
m_Width = m_ImageBackup.Width;
m_Height = m_ImageBackup.Height;
m_bmapOut = new Bitmap(m_Width, m_Height);
m_bmapIn = m_ImageBackup;
pictureBox1.Image = m_bmapIn;
}


private void JobCore_Click(object sender, EventArgs e)
{
DateTime dt = DateTime.Now;
int min = dt.Minute;
int sec = dt.Second;
int mili = dt.Millisecond;
lblStart.Text = "";
lblEnd.Text = "";
lblJob.Text = "";

lblStart.Text = "開始時間:" + min.ToString() + "_" + sec.ToString() + "_" + mili.ToString();
Refresh();

Bitmap bd = pictureBox1.Image as Bitmap;
Bitmap bs;
BitmapData bDataInS;
BitmapData bDataInD;
IntPtr Scan0_InS; // ピクセルデータの開始アドレス
IntPtr Scan0_InD; // ピクセルデータの開始アドレス
bs = new Bitmap(m_bmapIn);
bDataInS = bs.LockBits(new Rectangle(0, 0, bs.Width, bs.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Scan0_InS = bDataInS.Scan0; // ピクセルデータの開始アドレス

bDataInD = bd.LockBits(new Rectangle(0, 0, bd.Width, bd.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Scan0_InD = bDataInD.Scan0; // ピクセルデータの開始アドレス


m_SouPT = Scan0_InS;
m_DesPT = Scan0_InD;
m_Width = bd.Width;
m_Height = bd.Height;

if (sender == button2)
{

for(int j = 1; j < THREADCOUNT; j++)
{
m_ThreadJobFixFL[j] = true; //スレッド処理完了フラグ (0番以外は完了させておく)
m_ThreadJobFL[j] = false; //スレッド処理開始フラグ(0番起動 以外は停止)
}
for(int i = 0; i < 1000; i++) //スレッド0番(480ライン処理)のみ起動
{
m_ThreadJobFixFL[0] = false; //スレッド処理完了フラグ (0番以外は完了させておく)
m_ThreadJobFL[0] = true; //スレッド処理開始フラグ(0番起動 以外は停止)
while(IsThreadJobFix() == false ) //全スレッドの処理が完了するまで待機
{
Thread.Sleep(1);
}
}

}
else
{
m_ThreadJobFixFL[0] = true; //スレッド処理完了フラグ (0番は完了させておく)
m_ThreadJobFL[0] = false; //スレッド処理開始フラグ(0番停止 以外は起動)

for(int i = 0; i < 1000; i++) //スレッド1番2番(240ライン処理)のみ起動
{
for(int j = 1; j < THREADCOUNT; j++)
{
m_ThreadJobFixFL[j] = false; //スレッド処理完了フラグ (0番は完了させておく)
m_ThreadJobFL[j] = true; //スレッド処理開始フラグ(0番停止 以外は起動)
}
while(IsThreadJobFix() == false ) //全スレッドの処理が完了するまで待機
{
Thread.Sleep(1);
}
}
}

bd.UnlockBits(bDataInD);
bs.UnlockBits(bDataInS);

DateTime dt2 = DateTime.Now;
min = dt2.Minute;
sec = dt2.Second;
mili = dt2.Millisecond;
lblEnd.Text = "終了時間:" + min.ToString() + "_" + sec.ToString() + "_" + mili.ToString();;
TimeSpan tm = dt2.Subtract(dt);
lblJob.Text = "経過時間:" + tm.TotalSeconds.ToString();
//pictureBox1.Refresh();
Refresh();
}



//すべてのスレッドの処理が完了したらTrue
private bool IsThreadJobFix()
{
for(int i = 0; i < THREADCOUNT; i++)
{
if (m_ThreadJobFixFL[i] == false)
{
return false;
}
}

return true;
}

//スレッド向けコールバック関数(0番)
private static void ThreadMethod0()
{
m_MyObj.ThreadMainJob0();
}

//スレッド向けコールバック関数(1番)
private static void ThreadMethod1()
{
m_MyObj.ThreadMainJob1();
}

//スレッド向けコールバック関数(2番)
private static void ThreadMethod2()
{
m_MyObj.ThreadMainJob2();
}

//スレッド向けコールバック関数(3番)
private static void ThreadMethod3()
{
m_MyObj.ThreadMainJob3();
}

//スレッド向けコールバック関数(4番)
private static void ThreadMethod4()
{
m_MyObj.ThreadMainJob4();
}


//スレッドによるグレースケール処理
private void ThreadMainJob0()
{
while(m_ThreadOnFL == true)
{
if (m_ThreadJobFL[0] == false)
{
Thread.Sleep(1);
continue;
}

GrayScaleB(0, 480, m_SouPT, m_DesPT, m_Width, m_Height);
m_ThreadJobFL[0] = false;
m_ThreadJobFixFL[0] = true;
}
}

private void ThreadMainJob1()
{
while(m_ThreadOnFL == true)
{
if (m_ThreadJobFL[1] == false)
{
Thread.Sleep(1);
continue;
}

GrayScaleB(0, 120, m_SouPT, m_DesPT, m_Width, m_Height);
m_ThreadJobFL[1] = false;
m_ThreadJobFixFL[1] = true;
}
}

private void ThreadMainJob2()
{
while(m_ThreadOnFL == true)
{
if (m_ThreadJobFL[2] == false)
{
Thread.Sleep(1);
continue;
}

GrayScaleB(120, 240, m_SouPT, m_DesPT, m_Width, m_Height);
m_ThreadJobFL[2] = false;
m_ThreadJobFixFL[2] = true;
}
}

private void ThreadMainJob3()
{
while(m_ThreadOnFL == true)
{
if (m_ThreadJobFL[3] == false)
{
Thread.Sleep(1);
continue;
}

GrayScaleB(240, 360, m_SouPT, m_DesPT, m_Width, m_Height);
m_ThreadJobFL[3] = false;
m_ThreadJobFixFL[3] = true;
}
}

private void ThreadMainJob4()
{
while(m_ThreadOnFL == true)
{
if (m_ThreadJobFL[4] == false)
{
Thread.Sleep(1);
continue;
}

GrayScaleB(360, 480, m_SouPT, m_DesPT, m_Width, m_Height);
m_ThreadJobFL[4] = false;
m_ThreadJobFixFL[4] = true;
}
}

public void GrayScaleB(int startY, int endY, IntPtr ptS, IntPtr ptD, int tmpWidth, int tmpHeight)
{
int x, y;
int index;
byte PixelData;
byte red, green, blue;

int scanl = tmpWidth * 3;
unsafe
{
byte* ps = (byte*)ptS;
byte* pd = (byte*)ptD;
for (y = startY; y < endY; y++)
{
for (x = 0; x < scanl; x += 3)
{
index = (y * scanl) + x;

blue = ps[index ];
green = ps[index + 1];
red = ps[index + 2];
PixelData = (byte)(0.299f * ((float)red) + 0.587f * ((float)green) + 0.114f * ((float)blue));

pd[index] = PixelData;
pd[index + 1] = PixelData;
pd[index + 2] = PixelData;
}
}
}
}

}
}
[/csharp]