2016-04-14 37 views
0

在以下代碼中(用/ clr編譯)故意寫入控制檯,線程要麼凍結GUI,要麼不提供任何結果。Visual Studio WinForm C++線程不安全

歡迎任何想法。 還特別是這一行this-> Invoke(d,gcnew array {AA,BB}); 只有2個參數,代碼編譯。如果我根據委託需要嘗試3個參數,則代碼不會編譯。任何想法爲什麼?

請幫助。

#include <iostream> 
#include <stdlib.h> 
#using <System.dll> 
#using <System.Windows.Forms.dll> 
#using <System.Drawing.dll> 

using namespace System; 
using namespace System::ComponentModel; 
using namespace System::Threading; 
using namespace System::Windows::Forms; 

#define     NN 1000000 
unsigned long long  AA = 0; 
unsigned long long  BB = 99999999999999999ull; 
unsigned long long  PP[NN]; 

bool IsPrime(unsigned long long number) 
{ 
    if (number == 2 || number == 3) 
     return true; 

    if (number % 2 == 0 || number % 3 == 0) 
     return false; 

    int divisor = 6; 
    while (divisor * divisor - 2 * divisor + 1 <= number) 
    { 
     if (number % (divisor - 1) == 0) 
      return false; 

     if (number % (divisor + 1) == 0) 
      return false; 

     divisor += 6; 
    } 
    return true; 
} 

void NextPrime(unsigned long long a, unsigned long long * prime) 
{ 
    while (!IsPrime(++a)) 
    { 
    } 

    * prime = a; 
} 

void FindAllPrimes(unsigned long long a, unsigned long long b, unsigned long long * prime) 
{ 
    unsigned long long k, n; 
    n = 0; 
    for (k = a; k < b; k++) 
    { 
     if (IsPrime(k)) 
     { 
      prime[n] = k; 
      n++; 
      if (n >= 1000000) 
      { 
       break; 
      } 
     } 
    } 
} 

namespace MyNameSpace 
{ 
    public ref class Form1 : public Form 
{ 

delegate void Delegate_Call(unsigned long long a, unsigned long long b, unsigned long long * prime); 

    private: void Function_1() 
    { 
     FindAllPrimes(AA, BB, PP); 
    } 

    private: void Function_2() 
    { 
     this->Function_3(AA, BB, PP); 
    } 

    private: void Function_3(unsigned long long a, unsigned long long b, unsigned long long * prime) 
    { 
     if (this->textBox1->InvokeRequired) 
     { 
      Delegate_Call^ d = gcnew Delegate_Call(this, &Form1::Function_3); 

      this->Invoke(d, gcnew array<Object^> { AA, BB }); 

      int n = rand() % NN; 

      this->textBox1->Text = PP[n].ToString(); 

      for (int n = 0; n < NN; n++) 
       std::cout << PP[n] << std::endl; 
     } 
     else 
     { 
      FindAllPrimes(AA, BB, PP); 

      int n = rand() % NN; 
      this->textBox1->Text = PP[n].ToString(); 
      for (int n = 0; n < NN; n++) 
       std::cout << PP[n] << std::endl; 
     } 
    } 

    private: Thread^ Thread_A; 

    private: BackgroundWorker^ backgroundWorker1; 
    private: TextBox^ textBox1; 
    private: Button^ Button_DoNotKnow; 
    private: Button^ Button_UnSafeCall; 
    private: Button^ Button_SafeCall; 
    private: Button^ Button_BGWorker; 

    private: System::ComponentModel::IContainer^ components; 

    public: Form1() 
     { 
      components = nullptr; 
      InitializeComponent(); 
     } 

    protected: ~Form1() 
     { 
      if (components != nullptr) 
      { 
       delete components; 
      } 
     } 

    private: void InitializeComponent() 
     { 
      this->textBox1 = gcnew System::Windows::Forms::TextBox(); 
      this->Button_DoNotKnow = gcnew System::Windows::Forms::Button(); 
      this->Button_UnSafeCall = gcnew System::Windows::Forms::Button(); 
      this->Button_SafeCall = gcnew System::Windows::Forms::Button(); 
      this->Button_BGWorker = gcnew System::Windows::Forms::Button(); 
      this->backgroundWorker1 = gcnew System::ComponentModel::BackgroundWorker(); 
      this->SuspendLayout(); 
      // 
      // textBox1 
      // 
      this->textBox1->Location = System::Drawing::Point(30, 30); 
      this->textBox1->Name = "textBox1"; 
      this->textBox1->Size = System::Drawing::Size(310, 20); 
      this->textBox1->TabIndex = 0;    
      // 
      // Button_DoNotKnow 
      // 
      this->Button_DoNotKnow->Location = System::Drawing::Point(20, 70); 
      this->Button_DoNotKnow->Name = "Button_DoNotKnow"; 
      this->Button_DoNotKnow->TabIndex = 1; 
      this->Button_DoNotKnow->Text = "DoNotKnow"; 
      this->Button_DoNotKnow->Click += gcnew System::EventHandler(this, &Form1::Button_DoNotKnow_Click); 
      // 
      // Button_UnSafeCall 
      // 
      this->Button_UnSafeCall->Location = System::Drawing::Point(100, 70); 
      this->Button_UnSafeCall->Name = "Button_UnSafeCall"; 
      this->Button_UnSafeCall->TabIndex = 2; 
      this->Button_UnSafeCall->Text = "Unsafe Call"; 
      this->Button_UnSafeCall->Click += gcnew System::EventHandler(this, &Form1::Button_UnSafeCall_Click); 
      // 
      // Button_SafeCall 
      // 
      this->Button_SafeCall->Location = System::Drawing::Point(180, 70); 
      this->Button_SafeCall->Name = "Button_SafeCall"; 
      this->Button_SafeCall->TabIndex = 3; 
      this->Button_SafeCall->Text = "Safe Call"; 
      this->Button_SafeCall->Click += gcnew System::EventHandler(this, &Form1::Button_SafeCall_Click); 
      // 
      // Button_BGWorker 
      // 
      this->Button_BGWorker->Location = System::Drawing::Point(260, 70); 
      this->Button_BGWorker->Name = "Button_BGWorker"; 
      this->Button_BGWorker->TabIndex = 4; 
      this->Button_BGWorker->Text = "Safe BW Call"; 
      this->Button_BGWorker->Click += gcnew System::EventHandler(this, &Form1::Button_BGWorker_Click); 
      // 
      // backgroundWorker1 
      // 
      this->backgroundWorker1->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler(this, &Form1::backgroundWorker1_RunWorkerCompleted); 
      // 
      // Form1 
      // 
      this->ClientSize = System::Drawing::Size(380, 180); 
      this->Controls->Add(this->Button_BGWorker); 
      this->Controls->Add(this->Button_SafeCall); 
      this->Controls->Add(this->Button_UnSafeCall); 
      this->Controls->Add(this->Button_DoNotKnow); 
      this->Controls->Add(this->textBox1); 
      this->Name = "Form1"; 
      this->Text = "Form1"; 
      this->ResumeLayout(false); 
      this->PerformLayout(); 
    } 

    private: void Button_DoNotKnow_Click(Object^ sender, EventArgs^ e) 
    { 
     FindAllPrimes(AA, BB, PP); 

     for (int n = 0; n < NN; n++) 
      std::cout << PP[n] << std::endl; 
    } 

    private: void Button_UnSafeCall_Click(Object^ sender, EventArgs^ e) 
    { 
     this->Thread_A = gcnew Thread(gcnew ThreadStart(this, &Form1::Function_1)); 

     this->Thread_A->Start(); 
    } 

    private: void Button_SafeCall_Click(Object^ sender, EventArgs^ e) 
    { 
     this->Thread_A = gcnew Thread(gcnew ThreadStart(this, &Form1::Function_2)); 

     this->Thread_A->Start(); 
    } 

    private: void Button_BGWorker_Click(Object^ sender, EventArgs^ e) 
    { 
     this->backgroundWorker1->RunWorkerAsync(); 
    } 

    private: void backgroundWorker1_RunWorkerCompleted(Object^ sender, RunWorkerCompletedEventArgs^ e) 
    { 
     FindAllPrimes(AA, BB, PP); 

     for (int n = 0; n < NN; n++) 
      std::cout << PP[n] << std::endl; 
    } 

}; 
} 

[STAThread] 
int main() 
{ 
    Application::EnableVisualStyles(); 
    Application::Run(gcnew MyNameSpace::Form1()); 
} 

回答

0

首先,窗體掛起的原因是您要從UI線程向控制檯打印100萬行。嘗試將NN更改爲讓100說,你會看到掛起消失。如果你想保持NN 100萬,唯一的選擇是將其移動到非UI線程。

for (int n = 0; n < NN; n++) 
    std::cout << PP[n] << std::endl; 

第二個問題,涉及到的invoke是,該Invoke預計System::Object^陣列。沒有從unsigned long long*System::Object^的隱式轉換,所以我們必須將其轉換爲IntPtr,它將轉換爲System::Object^

private: void Function_3(unsigned long long a, unsigned long long b, unsigned long long * prime) 
{ 
    if (this->textBox1->InvokeRequired) 
    { 
     Delegate_Call^ d = gcnew Delegate_Call(this, &Form1::Function_3); 

     //this->Invoke(d, gcnew array<Object^> { AA, BB, IntPtr(PP) }); 

     // btw, you can use it also this way 
     this->Invoke(d, AA, BB, IntPtr(PP)); 

     //int n = rand() % NN; 

     // we are still on non UI thread so this will end in CrossThread eception ofcourse 
     //this->textBox1->Text = PP[n].ToString(); 

     //for (int n = 0; n < NN; n++) 
     // std::cout << PP[n] << std::endl; 
    } 
    else 
    { 
     FindAllPrimes(AA, BB, PP); 

     int n = rand() % NN; 
     this->textBox1->Text = PP[n].ToString(); 
     for (int n = 0; n < NN; n++) 
      std::cout << PP[n] << std::endl; 
    } 
} 
+0

非常感謝您的回答。我想繼續打印100萬行。這是爲了項目中的其他要求。我嘗試了您的更改,代碼正在控制檯上打印,但我無法移動GUI。或按任意按鈕(稍後我想添加一個按鈕以取消)您是否可以在打印到控制檯時幫助使GUI響應。你也可以寫一些代碼如何啓動一個無GUI線程,以及如何將函數調用移動到非GUI線程。先謝謝你。 – Hatems