第23講 BackgroundWorkerによるマルチスレッド
第5話 BackgroundWorker版素数探索ソフト解答例
#pragma once
#include <math.h>
#include<stdlib.h>
#include<set>
using namespace std;
int N;
int cn1,cn2,cn3,cn4;
int s1[25000000],s2[25000000],s3[25000000],s4[25000000];
namespace BackgroundWorkerによる素数探索 {
・
・
・
#pragma endregion
private: System::Void button1_Click_1(System::Object^ sender, System::EventArgs^
e) {
set<int> s;
int i,j,cn;
N=int::Parse(textBox1->Text);
s.clear();
s.insert(2);s.insert(3);s.insert(5);
for(i=0;i<cn1;i++){
s1[i]=0;
cn1=0;
}
for(i=0;i<cn2;i++){
s2[i]=0;
cn2=0;
}
for(i=0;i<cn3;i++){
s3[i]=0;
cn3=0;
}
for(i=0;i<cn4;i++){
s4[i]=0;
cn4=0;
}
DateTime^ hj=DateTime::Now; //開始時間
backgroundWorker1->RunWorkerAsync();
backgroundWorker2->RunWorkerAsync();
backgroundWorker3->RunWorkerAsync();
backgroundWorker4->RunWorkerAsync();
array<String^>^ w=gcnew array<String^>(10);
DateTime^ ow=DateTime::Now; //終了時間
i=0;
while(1){ //無駄打ち
i++;
if(i==100000000)break;
}
i=0;
while(1){
s.insert(s1[i]);
i++;
if(cn1<i)break;
}
i=0;
while(1){
s.insert(s2[i]);
i++;
if(cn2<i)break;
}
i=0;
while(1){
s.insert(s3[i]);
i++;
if(cn3<i)break;
}
i=0;
while(1){
s.insert(s4[i]);
i++;
if(cn4<i)break;
}
cn=0;
for(set<int>::iterator it=s.begin();it!=s.end();it++){
if(*it==0)it++;
w[cn%10]=(*it).ToString();
if(cn==cn1+cn2+cn3+cn4+2){
for(j=(cn%10)+1;j<10;j++){
w[j]=L"";
}
}
if(cn%10==9)dataGridView1->Rows->Add(w);
cn++;
}
dataGridView1->Rows->Add(w);
TimeSpan sa=ow->Subtract(*hj); //経過時間の計算
w[0]=L"計算時間"; w[1]=sa.TotalSeconds.ToString();
for(i=2;i<10;i++)w[i]=L"";
dataGridView1->Rows->Add(w);
w[0]=L"素数個数"; w[1]=(cn).ToString();
dataGridView1->Rows->Add(w);
w[0]=L"1余る";w[1]=cn1.ToString();w[2]=L"2余る";w[3]=cn2.ToString();w[4]=L"3余る";w[5]=cn3.ToString();w[6]=L"3余る";w[7]=cn4.ToString();
dataGridView1->Rows->Add(w);
int min;
min=cn1;
if(cn2<min)min=cn2;
if(cn3<min)min=cn3;
if(cn4<min)min=cn4;
w[0]=L"1余る";w[1]=(((double)cn1/(double)min)).ToString();w[2]=L"2余る";
w[3]=(((double)cn2/(double)min)).ToString();w[4]=L"3余る";w[5]=(((double)cn3/(double)min)).ToString();w[6]=L"4余る";
w[7]=(((double)cn4/(double)min)).ToString();
dataGridView1->Rows->Add(w);
}
private: System::Void backgroundWorker1_DoWork(System::Object^ sender,
System::ComponentModel::DoWorkEventArgs^ e) {
for (int i=6; i<=N; i+=5) {
if(sh(i)){
s1[cn1]=i;
cn1++;
}
}
}
private: System::Void backgroundWorker2_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
for (int i=7; i<=N; i+=5) {
if(sh(i)){
s2[cn2]=i;
cn2++;
}
}
}
private: System::Void backgroundWorker3_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
for (int i=8; i<=N; i+=5) {
if(sh(i)){
s3[cn3]=i;
cn3++;
}
}
}
private: System::Void backgroundWorker4_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
for (int i=9; i<=N; i+=5) {
if(sh(i)){
s4[cn4]=i;
cn4++;
}
}
}
static char sh(double n){
char h=1;
double a;
int b;
int c;
int i;
a=sqrt(n);
b=(int)a;
c=(int)n;
if(c % 2==0)h=0;
if(h==1){
for(i=3;i<=a;i=i+2){
if(c % i==0){
h=0;
break;
}
}
}
return(h);
}
};
}
while(1){ //無駄打ち
i++;
if(i==100000000)break;
}
は無駄打ちです。これですべてのスレッドが終了するまでの時間稼ぎをしているわけです。
さて、実験結果です。
探索範囲 | 100 | 1000 | 10000 | 100000 | 1000000 | 10000000 | |
マルチ4スレッド版 | 個数 | 25 | 168 | 1229 | 9592 | 78498 | 664579 |
時間 | 0.078 | 0.0312 | 0.0156 | 0.0156 | 0.1872 | 2.7144 | |
マルチ4スレッドBackgroundWorker版 | 個数 | 25 | 168 | 1229 | 9592 | 78498 | 664579 |
時間 | 0 | 0 | 0 | 0 | 0 | 0.0468 |
処理時間は、backgroundWorker1のようが速いようです。
実は、よく実験してみると無駄打ちさせても探索範囲が大きくなると、
結果が安定しません。if(i==100000000)break;
の数字を大きくすれば安定しますが、芸がありません。
終了通知を使ってもっとすっきりしたものができないか、
試行錯誤しましたが、私はその方法を発見できませんでした。
うまい方法があったら、教えて頂ければと思います。
訂正(2011/03/06)
第25講の第5話をアップして、
DateTime^ hj=DateTime::Now; //開始時間
backgroundWorker1->RunWorkerAsync();
backgroundWorker2->RunWorkerAsync();
backgroundWorker3->RunWorkerAsync();
backgroundWorker4->RunWorkerAsync();
array<String^>^ w=gcnew array<String^>(10);
DateTime^ ow=DateTime::Now; //終了時間
の
array<String^>^ w=gcnew array<String^>(10);
DateTime^ ow=DateTime::Now; //終了時間
の部分は、全く意味がないことに気がつきました。
理由は、BackgroundWorkerは、
現在の直線的な流れから、スレッドを分岐させるものでした。
スレッドに分岐した後も水面上の本体のプログラムの方(上手の緑の線)は処理が進んでしまいます。
各派生スレッドは時間のかかる処理ですから、派生スレッドが処理しているうちに、
array<String^>^ w=gcnew array<String^>(10);
DateTime^ ow=DateTime::Now; //終了時間
の処理が実行されてしまいます。
皆様を混乱させてことをお詫び申し上げます。
VC++には、スレッドが終了するまで待機させる命令はないんでしょうか。
私には、わかりません。
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座