第22講 素数探索を題材としたマルチスレッドプログラミングの学習
第8話 ParameterizedThreadStartによって初めの値を送る
新たにスレッドを生成するとき、
Thread^ A=gcnew Thread(gcnew ThreadStart(f)); を
Thread^ A=gcnew Thread(gcnew ParameterizedThreadStart(f)); にかえると、
A->Start(6); のように初めの値を送ることができます。
この値を受け取る関数側は、
static void f(Object^ 変数名)
のようにします。値を受け取るときの変数のタイプがObject^であると理解してください。
そして受け取るとき、例えば変数名がst、すなわち
static void f(Object^ st)なら、stを使うときは (Int32)st として使います。
つまり、Object^型を強制的にInt32型に変更して使うのです。
Int32型に変更すると、普通のint型の整数になります。
ですから、ParameterizedThreadStart使うと前の4スレッドは、
private: System::Void button1_Click(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; //開始時間
//スレッドの生成
Thread^ A=gcnew Thread(gcnew ParameterizedThreadStart(f));
Thread^ B=gcnew Thread(gcnew ParameterizedThreadStart(f));
Thread^ C=gcnew Thread(gcnew ParameterizedThreadStart(f));
Thread^ D=gcnew Thread(gcnew ParameterizedThreadStart(f));
//計算開始
A->Start(6);
B->Start(7);
C->Start(8);
D->Start(9);
//スレッドの終了を待つ
A->Join();
B->Join();
C->Join();
D->Join();
array<String^>^ w=gcnew array<String^>(10);
DateTime^ ow=DateTime::Now; //終了時間
for(i=0;i<=cn1;i++){
s.insert(s1[i]);
}
for(i=0;i<=cn2;i++){
s.insert(s2[i]);
}
for(i=0;i<=cn3;i++){
s.insert(s3[i]);
}
for(i=0;i<=cn4;i++){
s.insert(s4[i]);
}
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]=(cn1+cn2+cn3+cn4+3).ToString();
dataGridView1->Rows->Add(w);
}
static void f(Object^ st){
for (int i=(Int32)st; i<=N; i+=5) {
if(sh(i)){
if((Int32)st==6){
s1[cn1]=i;
cn1++;
}
if((Int32)st==7){
s2[cn2]=i;
cn2++;
}
if((Int32)st==8){
s3[cn3]=i;
cn3++;
}
if((Int32)st==9){
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);
}
となります。残念ながら、1本化すると、少し速度が落ちるようです。
といって、数%〜1割程度ですが。
6スレッドについてはご自分でお願いします。
これで第22講を終了し、第23講ではBackgroundWorkerによるマルチスレッドに挑戦します。
そして、第24講では新たにFormを派生させるマルチスレッドをご紹介します。
今後の講義予定を書いていて、ひとつ語り落とした問題があることを思い出しました。
『素数で割った余りで分ければ比較的均等にグループ分けできる』という仮説の検証です。
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e)の最後に
w[0]=L"素数個数"; w[1]=(cn1+cn2+cn3+cn4+3).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"1余る";w[3]=(((double)cn2/(double)min)).ToString();
w[4]=L"1余る";w[5]=(((double)cn3/(double)min)).ToString();w[6]=L"1余る";w[7]=(((double)cn4/(double)min)).ToString();
dataGridView1->Rows->Add(w);
}
ピンクを加えて実験し見ると
最小の数(min)と最大の数の差は、0.12%しかありませんでした。
すなわち、仮説『素数で割った余りで分ければ比較的均等にグループ分けできる』は検証されたわけです。
というより探索範囲を無限大まで持っていけば『素数で割った余りで分ければ均等にグループ分けできる』という仮説さえ可能です。
第22講第7話へ 第23講第1話へ
VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual
Basic入門基礎講座