Visual Studio WinForm C++线程不安全



在有意写入控制台的以下代码(使用/clr编译)中,线程要么冻结GUI,要么不给出任何结果。

欢迎提出任何想法。还特别是此行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());
}

首先,Form挂起的原因是您正在从UI线程向控制台打印100万行。试着把NN改为100,你会看到挂起的东西消失了。如果您想保留NN 100万,那么唯一的选择就是将其移动到非UI线程。

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

与调用相关的第二个问题是,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;
    }
}

最新更新