第23講 BackgroundWorkerによるマルチスレッド
第3話 BackgroundWorkerの練習の続き


各部分のコーティングは次の通りです。

private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i++)w+=i;
         w1=w.ToString();
}


private: System::Void backgroundWorker2_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=2;i<101;i+=2)w+=i;
         w2=w.ToString();
}

private: System::Void backgroundWorker3_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i+=2)w+=i;
         w3=w.ToString();
}

private: System::Void backgroundWorker4_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i++)w+=i*i;
         w4=w.ToString();
}



謎の現象の答えは、
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         backgroundWorker1->RunWorkerAsync();
         backgroundWorker2->RunWorkerAsync();
         backgroundWorker3->RunWorkerAsync();
         backgroundWorker4->RunWorkerAsync();
         label5->Text=w1;
         label6->Text=w2;
         label7->Text=w3;
         label8->Text=w4;
      }
だと、すべてのbackgroundWorkerが終了する前に
         label5->Text=w1;
         label6->Text=w2;
         label7->Text=w3;
         label8->Text=w4;
が実施されてしまい、また計算が終了していないbackgroundWorkerの部分が空欄になってしまうのです。
この現象を改善するには、
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
         backgroundWorker1->RunWorkerAsync();
         backgroundWorker2->RunWorkerAsync();
         backgroundWorker3->RunWorkerAsync();
         backgroundWorker4->RunWorkerAsync();
      }
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i++)w+=i;
         w1=w.ToString();
         label5->Text=w1;
}
private: System::Void backgroundWorker2_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=2;i<101;i+=2)w+=i;
         w2=w.ToString();
         label6->Text=w2;
}
private: System::Void backgroundWorker3_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i+=2)w+=i;
         w3=w.ToString();
         label7->Text=w3;
}
private: System::Void backgroundWorker4_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
         long w=0;
         int i;
         for(i=1;i<101;i++)w+=i*i;
         w4=w.ToString();
         label8->Text=w4;
}
として各スレッドで表示させれば解決しそうなものですが、ところが各Void backgroundWorker?_DoWorkでは、
labelのTextに表示させることができないのです。
そこで、System::Void backgroundWorker?_RunWorkerCompletedを使います。
まず、次のようにコーティングし直してください。
#pragma endregion
      String^ w1;String^ w2;String^ w3;String^ w4;
   private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           backgroundWorker1->RunWorkerAsync();
           backgroundWorker2->RunWorkerAsync();
           backgroundWorker3->RunWorkerAsync();
           backgroundWorker4->RunWorkerAsync();
   }
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
        long w=0;
        int i;
        for(i=1;i<101;i++)w+=i;
        w1=w.ToString();
}
private: System::Void backgroundWorker1_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) {
        label5->Text = w1;
}

private: System::Void backgroundWorker2_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
        long w=0;
        int i;
        for(i=2;i<101;i+=2)w+=i;
        w2=w.ToString();
}
private: System::Void backgroundWorker2_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) {
        label6->Text = w2;
}

private: System::Void backgroundWorker3_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
        long w=0;
        int i;
        for(i=1;i<101;i+=2)w+=i;
        w3=w.ToString();
}
private: System::Void backgroundWorker3_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) {
        label7->Text = w3;
}

private: System::Void backgroundWorker4_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
        long w=0;
        int i;
        for(i=1;i<101;i++)w+=i*i;
        w4=w.ToString();
}
private: System::Void backgroundWorker4_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) {
        label8->Text = w4;
}

そして、デザインに戻りを右クリックして、プロパティをクリックします。
次にプロパティウィンドウのイベントアイコンをクリックします。
そして、青で囲んであるところをダブるクリックして、
backgroundWorker1_RunWorkerCompletedを選択してください。
backgroundWorker2についても同様にしてbackgroundWorker2_RunWorkerCompleted
残りも番号が対応するのようにRunWorkerCompletedを選んでください。
backgroundWorker1_RunWorkerCompletedを利用すると、各スレッドからlabelのTextに書き込めるようになり、
前の不可解な現象が消えます。


ビルドしてうまくいっていることを確認したらさらに次のように改良してください。
まずForm1のlabelのテキストをすべて消して
のようにします。
さらに、labelとTextBoxを加えて

と変更します。
プログラムソースも
#pragma once
long N;
namespace backgroundWorker練習 {
       ・
       ・
       ・
#pragma endregion
      String^ w1;String^ w2;String^ w3;String^ w4;
   private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
     N=int::Parse(textBox1->Text);
     backgroundWorker1->RunWorkerAsync();
           ・
           ・
           ・
と変更し、ビルドしてTextBoxに値を入力してボタンを押すと、

となるように皆さん工夫して下さい。
そして、TextBoxに入れる値を大きくするとCPU使用率が100%であることが確認できます。



第23講第2話へ 第23講第4話へ



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