C#的ApartmentState的属性:[STAThread]

每个Thread都有一个关于ApartmentState的属性,可以把它设置为:STA或者MTA,或者UNKNOWN。
当你想指定工程的启动窗口的时候,你需要在该窗口类中申明一个Main()方法,并为这个方法设置[STAThread]属性。

[STAThread]是Single Thread Apartment单线程套间的意思,是一种线程模型,用在程序的入口方法上
(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA。用在其他方法上不产生影响。
在aspx页面上可以使用AspCompat = "true" 来达到同样的效果。这个属性只在 Com Interop 有用,
如果全部是 managed code 则无用。简单的说法:[STAThread]指示应用程序的默认线程模型是单线程单元 (STA)。
启动线程模型可设置为单线程单元或多线程单元。如果未对其进行设置,则该线程不被初始化。也就是说如果你用的.NET Framework,
并且没有使用COM Interop,一般不需要这个Attribute。其它的还有MTA(多线程套间)、Free Thread(自由线程)。
单线程套间,简单来说所有对于单线程套间中对象的访问都是通过消息来传递的,所以同一时间只有一个线程能够访问单线程套间中的对象。

例如:
class MainClass
{
 [STAThread]
static void Main(string[] args)
{
 Teacher teacher = new Teacher();
 Student student = new Student();
 student.AdviseDelegateInstance = new Student.AdviseDelegate(teacher.Advise);
 Console.WriteLine("Student got 49");
 student.SetScore(49);
 Console.WriteLine("Student got 87");
 student.SetScore(87);
 Console.ReadLine();
 }
 }

表示这个Main程序被一个单线程套间包住,且Main的执行,一次只能被一个线程占用,这个线程未执行完,别的线程是没办法调用的。

http://blog.csdn.net/qilang/archive/2006/06/06/775605.aspx

STA不是单线程的意思.英文为single threaded apartment.是一种套间(或译为公寓)线程模式.

sta thread并不表明应用程式的类型,和应用程序不搭界,恰相反,一个应用程序可以有多个线程.每个线程也可以有多个组件或对象.以前win16位系统的组件线程模式才真正是单线程.这是一种被淘汰了的模式.
线程模式用于处理组件在多线程的环境里并行与并互的方式.比如套间线程(STAThread)模式中接口跨线程传递必须被调度(Marshal),不调度直传肯定会失败!而MTA或FreeThread模式中的接口可以不经调度直接传递.
这种调度在特定的环境中非常影响性能(可有几百倍之差).如VB里只支持STAThread模式.FreeThread模式的组件会在里面表现成和跨进程一样慢!
线程模式是微软的COM基础中的极其重要的概念.一定要吃透!
我对.net真是一窍不通(没空去弄,对不起微软去年的奖赏).但我可以肯定,C#中的[STAThread]属性是应用程序的套间初始化代码.可以直接理解成SDK里的
CoInitialize(NULL);
初始一个STA套间实际上是相当于开了一个消息窗口,所有调用经此窗口过程调度到组件内.
同理[MTAThread](不知有没有这个属性,自已去查)
可以理解成
CoInitializeEx(NULL,COINIT_MULTITHREADED )
这经常是一个对初入com大门的人来说,有一定难度但必须过的一道关.

打开一个其他人写的C#程序,为了下面的讲解,我把这个程序叫作”DeltaEngine”。DeltaEngine会调用一个本地的程序集,并处理其中某些事件。然后建一个工程,把DeltaEngine作为库项目引用,这个工程又被一个VB程序引用。我把这个VB程序叫做"VBApp"。所以,引用结构就像:

VBApp (VB) -> DeltaEngine (C#) -> NativeCode

当我把VBApp作为启动程序运行时,它会一直等待NativeCode里面的事件在DeltaEngine中被处理。我注意到,如果我把DeltaEngine作为启动程序来运行的话,事件就会像预期那样得到处理。我花了很多时间想解决这个问题,但还是很困惑。

最后有人指出,VB项目的默认线程模型是单线程套间(SingleThreaded Apartment),而C#项目的默认线程模型是多线程套间 (Multithreaded Apartment)。因为DeltaEngine最初是作为C#工程开发的,被默认为使用MTA。当使用VBApp作为启动程序调用DeltaEngine时,DeltaEngine就会使用STA。因为这样,DeltaEngine就会开始等待其实它已经唤起的事件,所以DeltaEngine会一直等待下去。如果我把DeltaEngine作为启动程序运行,它就会使用MTA并且会像预期那样工作。

解决的方法就是把MTAThreadAttribute加进VBApp的主函数里面。如下:

<MTAThread> Sub Main()

类似,如果你想把STAThread attribute加进C#的主方法里面,如下:

[STAThread]

static void Main()

WindowsForms程序要求使用STA,所以创建C# Winapp后,你可以在Program.cs看见像这样的代码。

我就不重复一些已经有的关于STATread 和MTAThread的文件,所以我给出下面的一些link可以学到更多关于STATread 和MTAThread的东西。

C# 中WindowsForm 的初始化信息 [STAThread]
static class Program

{

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new Form1());

}

 

 

}

 

以上的代码是VS 2005中默认的初始化信息.

Application.EnableVisualStyles();

简单的说就是让你的控件显示出来.当然是在WindowsForm 中

此方法为应用程序启用可视样式。如果控件和操作系统支持视觉样式,则控件将以视觉样式进行绘制。若要使 EnableVisualStyles 生效,必须在应用程序中创建任何控件之前调用它;EnableVisualStyles 通常是 Main 函数的第一行.

 

下面的代码示例演示如何在 Main 函数中调用 EnableVisualStyles 来启用应用程序的视觉样式

对于支持 FlatStyle 属性的控件,请确保将 FlatStyle 属性设置为 FlatStyle.System 值。

 


using System;

using System.Drawing;

using System.Windows.Forms;

 

namespace VStyles

{

public class Form1 : System.Windows.Forms.Form

{

 

private System.Windows.Forms.Button button1;

 

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.Run(new Form1());

}

 

public Form1()

{

this.button1 = new System.Windows.Forms.Button();

this.button1.Location = new System.Drawing.Point(24, 16);

this.button1.Size = new System.Drawing.Size(120, 100);

this.button1.FlatStyle = FlatStyle.System;

this.button1.Text = "I am themed.";

 

// Sets up how the form should be displayed and adds the controls to the form.

this.ClientSize = new System.Drawing.Size(300, 286);

this.Controls.Add(this.button1);

 

this.Text = "Application.EnableVisualStyles Example";

 

}

}

}

由于很多COM在.NET环境下如果使用多线程的话,会导致引用的COM不能正常运行,而如果不声明程序为STAThread的话,.NET就会自动使用多线程来提高效率,这样就会导致不可预知的后果。

posted @ 2021-03-29 11:31  左正  阅读(339)  评论(0编辑  收藏  举报