第19講 .NETによるマルチスレッドプログラミング
第6話 .NET による普遍版魔方陣自動生成マルチスレッド
コード例
#include<iostream>
using namespace std;
using namespace System;
using namespace System::Threading;
void f0();
static void t1();
static void t2();
static void t3();
static void t4();
void f11(char g);
void f12(char g);
void f13(char g);
void f14(har g);
void f21();
void f22();
void f23();
void f24();
void g();
int n,cn1,cn2,cn3,cn4;
int m1[2000][10][10],m2[2000][10][10],m3[2000][10][10],m4[2000][10][10],a1[10][10],a2[10][10],a3[10][10],a4[10][10],x[100],y[100];
int main(){
  cout<<"何次魔方陣を作成させるのかキーボードから入力してください。"<<endl;
  cout<<"次数=";
  scanf("%d",&n);
  DateTime^ hj=DateTime::Now;
  f0();
  Thread^ p=gcnew Thread(gcnew ThreadStart(t1));
  Thread^ q=gcnew Thread(gcnew ThreadStart(t2));
  Thread^ r=gcnew Thread(gcnew ThreadStart(t3));
  Thread^ s=gcnew Thread(gcnew ThreadStart(t4));
  p->Start();
  q->Start();
  r->Start();
  s->Start();
  p->Join();
  q->Join();
  r->Join();
  s->Join();
  g();
  cout<<n<<"次魔方陣が"<<cn1+cn2+cn3+cn4<<"個できました。"<<endl;
  DateTime^ ow=DateTime::Now;
  TimeSpan sa=ow->Subtract(*hj);
  cout<<"計算時間は"<<sa.TotalSeconds<<"秒です。"<<endl;
  /*
  int i,j,c[10][10];
  for(i=0;i<n*n;i++){
    c[y[i]][x[i]]=i;
  }
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      if(c[i][j]<10)cout<<" "<<c[i][j]<<" ";
      if(c[i][j]>=10)cout<<c[i][j]<<" ";
    }
    cout<<endl;
  }
  */
}
void f0(){
  int i,j,c=0;
  int b[10][10];
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      b[i][j]=-1;
    }
  }
  for(i=0;i<n;i++){
    b[i][i]=i;
  }
  c=n-1;
  for(i=0;i<n;i++){
    if(b[i][n-1-i]==-1){
      c++;
      b[i][n-1-i]=c;
    }
  }
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      if(b[i][j]==-1){
        c++;
        b[i][j]=c;
      }
    }
  }
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      x[b[i][j]]=j;
      y[b[i][j]]=i;
    }
  }
}
void t1(){
  cn1=0;
  f11(0);
}
void t2(){
  cn2=0;
  f12(0);
}
void t3(){
  cn3=0;
  f13(0);
}
void t4(){
  cn4=0;
  f14(0);
}
void f11(char g){
  register char i,j,ii;
  char h,w;
  for(i=1;i<n*n+1;i++){
    if(g==0 && i>n*n/4)break;
    a1[y[g]][x[g]]=i;
    h=1;
    if(g>0){
      for(j=0;j<g;j++){
        if(a1[y[g]][x[g]]==a1[y[j]][x[j]]){
          h=0;
          break;
        }
      }
    }
    if(h==1 && y[g]==n-1 && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-1 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[n-1-j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==0 && x[g]==n-2){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>n && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-2 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>2*n-1 && y[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a1[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }

    if(h==1){
      if(g+1<n*n){
        f11(g+1);
       }
       else{
        cn1++;
        f21();
        if(cn1==2000)break;
       }
    }
    if(cn1==2000)break;
  }
}
void f12(char g){
  register char i,j;
  char h,w,k=1;
  for(i=1;i<n*n+1;i++){
    if(g==0){
      if(k==1){
        i+=n*n/4;
        k=0;
      }
      if(i>n*n/2)break;
    }
    a2[y[g]][x[g]]=i;
    h=1;
    if(g>0){
      for(j=0;j<g;j++){
        if(a2[y[g]][x[g]]==a2[y[j]][x[j]]){
          h=0;
          break;
        }
      }
    }
    if(h==1 && y[g]==n-1 && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-1 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[n-1-j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==0 && x[g]==n-2){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>n && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-2 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>2*n-1 && y[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a2[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }

    if(h==1){
      if(g+1<n*n){
        f12(g+1);
       }
       else{
        cn2++;
        f22();
        if(cn2==2000)break;
       }
    }
    if(cn2==2000)break;
  }
}
void f13(char g){
  register char i,j;
  char h,w,k=1;
  for(i=1;i<n*n+1;i++){
    if(g==0){
      if(k==1){
        i+=n*n/2;
        k=0;
      }
      if(i>3*n*n/4)break;
    }
    a3[y[g]][x[g]]=i;
    h=1;
    if(g>0){
      for(j=0;j<g;j++){
        if(a3[y[g]][x[g]]==a3[y[j]][x[j]]){
          h=0;
          break;
        }
      }
    }
    if(h==1 && y[g]==n-1 && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-1 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[n-1-j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==0 && x[g]==n-2){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>n && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-2 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>2*n-1 && y[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a3[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }

    if(h==1){
      if(g+1<n*n){
        f13(g+1);
       }
       else{
        cn3++;
        f23();
        if(cn3==2000)break;
       }
    }
    if(cn3==2000)break;
  }
}
void f14(char g){
  register char i,j;
  char h,w,k=1;
  for(i=1;i<n*n+1;i++){
    if(g==0){
      if(k==1){
        i+=3*n*n/4;
        k=0;
      }
    }
    a4[y[g]][x[g]]=i;
    h=1;
    if(g>0){
      for(j=0;j<g;j++){
        if(a4[y[g]][x[g]]==a4[y[j]][x[j]]){
          h=0;
          break;
        }
      }
    }
    if(h==1 && y[g]==n-1 && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-1 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[n-1-j][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==0 && x[g]==n-2){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>n && x[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[y[g]][j];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && y[g]==n-2 && x[g]==0){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }
    if(h==1 && g>2*n-1 && y[g]==n-1){
      w=0;
      for(j=0;j<n;j++){
        w+=a4[j][x[g]];
      }
      if(w!=n*(n*n+1)/2)h=0;
    }

    if(h==1){
      if(g+1<n*n){
        f14(g+1);
       }
       else{
        cn4++;
        f24();
        if(cn4==2000)break;
       }
    }
    if(cn4==2000)break;
  }
}
static void f21(){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      m1[cn1-1][i][j]=a1[i][j];
    }
  }
}
static void f22(){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      m2[cn2-1][i][j]=a2[i][j];
    }
  }
}
static void f23(){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      m3[cn3-1][i][j]=a3[i][j];
    }
  }
}
static void f24(){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      m4[cn4-1][i][j]=a4[i][j];
    }
  }
}
void g(){
  int i,j,k;
  for(i=0;i<cn1;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m1[i][j][k]<10)cout<<" "<<m1[i][j][k]<<" ";
        if(m1[i][j][k]>=10)cout<<m1[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn2;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m2[i][j][k]<10)cout<<" "<<m2[i][j][k]<<" ";
        if(m2[i][j][k]>=10)cout<<m2[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn3;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m3[i][j][k]<10)cout<<" "<<m3[i][j][k]<<" ";
        if(m3[i][j][k]>=10)cout<<m3[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn4;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m4[i][j][k]<10)cout<<" "<<m4[i][j][k]<<" ";
        if(m4[i][j][k]>=10)cout<<m4[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
}
入門
シングルスレッド版は私のパソコンでは約48秒でしたから、
27/48と短縮されています。
void g(){
  int i,j,k;
  for(i=0;i<cn1;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m1[i][j][k]<10)cout<<" "<<m1[i][j][k]<<" ";
        if(m1[i][j][k]>=10)cout<<m1[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn2;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m2[i][j][k]<10)cout<<" "<<m2[i][j][k]<<" ";
        if(m2[i][j][k]>=10)cout<<m2[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn3;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m3[i][j][k]<10)cout<<" "<<m3[i][j][k]<<" ";
        if(m3[i][j][k]>=10)cout<<m3[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
  for(i=0;i<cn4;i++){
    for(j=0;j<n;j++){
      for(k=0;k<n;k++){
        if(m4[i][j][k]<10)cout<<" "<<m4[i][j][k]<<" ";
        if(m4[i][j][k]>=10)cout<<m4[i][j][k]<<" ";
      }
      cout<<endl;
    }
    cout<<endl;
  }
}
の部分は、コンソールへの表示です。
コンソールの表示はシングルスレッドになっているので、
コンソールへの魔方陣の表示まで入れると、
純粋な4スレッドとシングルスレッドの比較になりません。
そこで、4スレッドもシングルスレッドも魔方陣を表示しないように変更いますと、
4スレッド
マルチスレッド
シングルスレッド
シングルスレッド
時間比は15.6579/40.5883で約2.65倍の速さになっています。
4倍までは行きませんが、シングルスレッドよりずっと速いことがわかります。

尚、速度比を比べるときは3次と4次のみが有効です。
5次は、何百日も、もしかすると何百年もパソコンに計算させないと全部の答えを発見できないからです。
6次以降は、1億年計算させても終わらないでしょう。
10次あたりは宇宙時間(宇宙の始まりから終わりまでの時間)計算させてもすべての魔方陣をパソコンは発見できないでしょう。
ですから、今回のプログラムでは4次が限界なのです。

次話ではスレッド起動時に引数を送れるように改良します。
引数を送れると今回
void f11(char g);
void f12(char g);
void f13(char g);
void f14(har g);
void f21();
void f22();
void f23();
void f24();
4つになってしまった関数を1つにまとめることができます。
引数を送れるようにするには
  Thread^ p=gcnew Thread(gcnew ParameterizedThreadStart(t));
  Thread^ q=gcnew Thread(gcnew ParameterizedThreadStart(t));
  Thread^ r=gcnew Thread(gcnew ParameterizedThreadStart(t));
  Thread^ s=gcnew Thread(gcnew ParameterizedThreadStart(t));
  p->Start(0);
  q->Start(1);
  r->Start(2);
  s->Start(3);
などとします。Parameterizedを加えるとスレッド開始時に引数を送れるのです。

引数を受け取る関数は
void t(Object^ a);
とします。つまり、引数はObject^型ということです。
関数t内で使うときは、
void t(Object^ a){
  int i;
  i=(Int32)a;

のようにキャスト(強制変換)する必要があります。

では皆さん改良を試みてください。

第5話へ 第7話へ

戻る

C言語 C++講義第1部へ
VB講義へ
VB講義基礎へ

vc++講義へ第1部へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)