为什么我的多线程C++。NET应用程序仅在visual Studio之外执行时崩溃? 我创建了一个非常简单的C++ .NET应用程序,它使用托管代码和非托管代码来复制我的问题。
当用户单击一个按钮时,一个新线程应该会产生并执行一些耗时的任务,同时通过状态更新返回到我的主线程 此代码在Visual Studio Express 2010内部编译并成功执行。也就是说,当我单击“播放”按钮时,我的项目构建和执行不会崩溃。但是,如果我转到可执行文件所在的发布文件夹并运行它,那么一旦单击按钮,应用程序就会崩溃。我正在使用/clr编译,并处于发布模式 我创建一个表单并添加一个按钮。Form1.h的代码如下所示:为什么我的多线程C++。NET应用程序仅在visual Studio之外执行时崩溃? 我创建了一个非常简单的C++ .NET应用程序,它使用托管代码和非托管代码来复制我的问题。,.net,c++,clr,unmanaged,managed,.net,C++,Clr,Unmanaged,Managed,当用户单击一个按钮时,一个新线程应该会产生并执行一些耗时的任务,同时通过状态更新返回到我的主线程 此代码在Visual Studio Express 2010内部编译并成功执行。也就是说,当我单击“播放”按钮时,我的项目构建和执行不会崩溃。但是,如果我转到可执行文件所在的发布文件夹并运行它,那么一旦单击按钮,应用程序就会崩溃。我正在使用/clr编译,并处于发布模式 我创建一个表单并添加一个按钮。Form1.h的代码如下所示: #pragma once #include "core.h" #in
#pragma once
#include "core.h"
#include <Windows.h>
#include <process.h>
namespace RepErr {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
int x;
/// <summary>
/// Summary for Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button1;
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->button1 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(104, 62);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(75, 23);
this->button1->TabIndex = 0;
this->button1->Text = L"button1";
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(276, 160);
this->Controls->Add(this->button1);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
core *o1 = new core();
unsigned uiThread1ID;
HANDLE hth1 = (HANDLE)_beginthreadex(NULL, 0, core::ThreadStaticEntryPoint, o1, CREATE_SUSPENDED, &uiThread1ID);
ResumeThread( hth1 );
}
public:
static void* callback(int smallIndex) {
x = smallIndex;
void* dtpage = NULL;
return dtpage;
}
delegate void* myCALLBACKDelegate(int smallIndex);
static GCHandle gch;
//static constructor, initialize delegate here
static Form1() {
myCALLBACKDelegate^ fp=gcnew myCALLBACKDelegate(callback);
gch = GCHandle::Alloc(fp);
formCallback = static_cast<myCALLBACK>(Marshal::GetFunctionPointerForDelegate(fp).ToPointer());
}
};
}
这是restr.cpp:
// RepErr.cpp : main project file.
#include "stdafx.h"
#include "Form1.h"
using namespace RepErr;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
return 0;
}
//restr.cpp:主项目文件。
#包括“stdafx.h”
#包括“表格1.h”
使用名称空间资源库;
[属性]
int main(数组^args)
{
//在创建任何控件之前启用Windows XP视觉效果
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
//创建主窗口并运行它
应用程序::运行(gcnewform1());
返回0;
}
程序正在崩溃,因为formCallback
为空(因此core::doCall
取消对空指针的引用)formCallback
为空,因为初始化它的Form1
静态构造函数从未运行
您可以通过向Form1
静态构造函数添加以下行来演示这一点:
static Form1() {
// ... other initialisation ...
MessageBox::Show(((int) formCallback).ToString("x8"));
}
在调试版本(或在VS调试器下运行的版本)中,将显示一个带有函数指针值的MessageBox。在发布版本中(不在调试器下),此对话框不会显示,因为静态构造函数未运行
静态构造函数未运行,因为类型已标记。这意味着“该类型的初始值设定项方法在首次访问为该类型定义的任何静态字段时或之前执行”。如果没有访问任何静态字段的权限,那么静态构造函数就不需要运行(在发布版本中,它也不需要运行)
根据,这是设计的。解决方法是在实例Form1
构造函数中访问您类型的静态字段,这将强制静态构造函数运行,从而正确初始化formCallback
:
static int s_dummy;
public:
Form1()
{
// force static constructor to run now
s_dummy = 0;
InitializeComponent();
}
或者(我建议),使用该类创建一个新的托管线程;这将避免使用托管委托、GCHandle、
formCallback
全局函数指针和静态构造函数。从托管线程中,如果需要执行非托管代码,可以调用本机C++。当然,您知道,在单击按钮时创建线程通常是一个非常糟糕的想法,对吗?尝试快速连续单击它……是的,这是一个简单的演示。:)我可以禁用生成新线程,直到使用线程管理器完成以前生成的线程为止。@Ronald:当然,停止这种滥用也很容易……对给定的代码不进行重新生成,也看不到问题。@Hans你能想到任何可能是我的机器/环境造成的吗?使用Express 2010编译?Windows7家庭版?等等?非常感谢!我的第一次尝试失败了,因为我愚蠢地将静态s_伪变量放在文件范围而不是Form1类中。移动它并修复它。谢谢你在线程课程上的指导。:)
static Form1() {
// ... other initialisation ...
MessageBox::Show(((int) formCallback).ToString("x8"));
}
static int s_dummy;
public:
Form1()
{
// force static constructor to run now
s_dummy = 0;
InitializeComponent();
}