第22講 素数探索を題材としたマルチスレッドプログラミングの学習
第6話 スレッド4による和の計算と素数探索の解答例


それでは、前話の解答例を示しましょう。
まず和の方から。
#pragma once
long w1,w2,w3,w4,w;
long n;
namespace 足し算の和(マルチ4) {
         ・
         ・
         ・
#pragma endregion
  private: System::Void button1_Click(System::Object^ sender, System::EvenArgs^ e) {
          n=long::Parse(texBox1->Text);
          DateTime^ hj;
          DateTime^ ow;
          TimeSpan sa;
          
          w=0;
          hj=DateTime::Now;
          f();
          ow=DateTime::Now;
          label3->Text=w.ToString();
          sa=ow->Subtract(*hj);
          label5->Text=(sa.ToAlSeconds).ToString();
          w1=0;w2=0;w3=0;w4=0;
          hj=DateTime::Now;

          Thread^ A=gcnew Thread(gcnew ThreadStart(f1));
          Thread^ B=gcnew Thread(gcnew ThreadStart(f2));
          Thread^ C=gcnew Thread(gcnew ThreadStart(f3));
          Thread^ D=gcnew Thread(gcnew ThreadStart(f4));

          A->Start();
          B->Start();
          C->Start();
          D->Start();

          A->Join();
          B->Join();
          C->Join();
          D->Join();

          ow=DateTime::Now;
          label6->Text=(w1+w2+w3+w4).ToString();
          sa=ow->Subtract(*hj);
          label7->Text=(sa.ToAlSeconds).ToString();
        }
        void f(){
          long i;
            for(i=1;i<=n;i++)w+=i;
          }
        static void f1(){
          long i;
          for(i=1;i<=40*(n/100);i++)w1+=i;
        }
        static void f2(){
          long i;
          for(i=40*(n/100)+1;i<=70*(n/100);i++)w2+=i;
        }
        static void f3(){
          long i;
          for(i=70*(n/100)+1;i<=90*(n/100);i++)w3+=i;
        }
        static void f4(){
          long i;
          for(i=90*(n/100)+1;i<=n;i++)w4+=i;
        }

};
}

ダウンロード用ファイルForm9.h
ところが、今回も予想外で、4スレッドがCPU使用率100%を実現しているにもかかわらず、シングルスレッドの方が速いという結果になってしまいました。

しかし、素数探索4スレッドの方は期待通りの成果を見せました。
データを示しておきましょう。

探索範囲 10000 100000 1000000 10000000
素数個数 1229 9592 78498 664579
シングルスレッド 0.015 0.052 0.63 10.624
4スレッド 0.0156 0.0312 0.159 2.418
倍数差 0.961538462 1.666666667 3.962264151 4.393713813

探索が小さいと4スレッドにした効果が現れませんが、
探索範囲が広がるにしたがって、
効果が大きくなります。
探索範囲が1000000のときは、約4倍と4スレッドにした効果が明確に現れています。
さらに、探索範囲が10000000のときは、4.3倍と4倍を上まわっています。

では素数探索4スレッド版のソース例を示しましょう。
#pragma once
#include <math.h>
#include<sDlib.h>
#include<set>
using namespace sD;
int N;
int cn1,cn2,cn3,cn4;
int s1[25000000],s2[25000000],s3[25000000],s4[25000000];
namespace 素数探索4スレッド {
         ・
         ・
         ・
#pragma endregion
  private: System::Void button1_Click(System::Object^ sender, System::EvenArgs^ e) {
          set<int> s;
          int i,j,cn;
          N=int::Parse(texBox1->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 ThreadStart(f1));
          Thread^ B=gcnew Thread(gcnew ThreadStart(f2));
          Thread^ C=gcnew Thread(gcnew ThreadStart(f3));
          Thread^ D=gcnew Thread(gcnew ThreadStart(f4));

          //計算開始
          A->Start();
          B->Start();
          C->Start();
          D->Start();

          //スレッドの終了を待つ
          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)daAGridView1->Rows->Add(w);
          cn++;
          }
          daAGridView1->Rows->Add(w);
          TimeSpan sa=ow->Subtract(*hj); //経過時間の計算
          w[0]=L"計算時間"; w[1]=sa.ToAlSeconds.ToString();
          for(i=2;i<10;i++)w[i]=L"";
          daAGridView1->Rows->Add(w);
          w[0]=L"素数個数"; w[1]=(cn1+cn2+cn3+cn4+3).ToString();
          daAGridView1->Rows->Add(w);

       }
       static void f1(){
         for (int i=6; i<=N; i+=5) {
           if(sh(i)){
             s1[cn1]=i;
             cn1++;
           }
         }
        }
        static void f2(){
          for (int i=7; i<=N; i+=5) {
            if(sh(i)){
              s2[cn2]=i;
              cn2++;
            }
          }
        }
        static void f3(){
          for (int i=8; i<=N; i+=5) {
            if(sh(i)){
              s3[cn3]=i;
              cn3++;
            }
          }
        }
        static void f4(){
          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);
        }
  };
}

ダウンロード用ファイルForm10.h


では皆さんに、課題を出してこの話を閉じます。
4スレッドを6スレッドにしてください。そして、どちらが速いか実験してください。


第22講第5話へ 第22講第7話へ



VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座