.NET Threading Model(STA and MTA)

最近看了一些多线程方面的咚咚,说说自己的认识,抛砖引玉。
参考资料:
http://www.yesky.com/20010207/158097.shtml
http://www.ftponline.com/china/XmlFile.aspx?ID=242
http://research.microsoft.com/~chadv/java_com2.htm
http://blogs.msdn.com/jfoscoding/archive/2005/04/07/406341.aspx


.NET支持两种线程模型:STA和MTA。
STA(single threaded apartments)。apartment只是一个逻辑上的概念,它可以包含一个或多个线程。一个AppDomain可以包括一个或多个apartment。STA是指该apartment中只能包含一个thread。
MTA(multi threaded apartments)。指该apartment中可以包含多个thread。
STA and MTA 之间最大的区别就是MTA 可以在同一个apartment 中使用所有的共享资源并发执行多个线程。 而多个STA虽然可以共享数据,但是不能并发执行线程,存在性能问题。

线程的创建:
当创建一个新的STA线程时,CLR会在该AppDomain中创建一个apartment和thread(从属于该apartment)。如果是创建MTA线程,则会CLR会检查该AppDomain是否存在一个存放MTA的apartment,如果存在仅创建该线程到该MTA中,否则就创建一个MTA和thread(从属于该apartment)。
我们可以设置线程的属性。例如 t.ApartmentState = ApartmentState.STA;

线程的使用区别:
我们应该仅仅在访问STA-based 的COM组件时才使用STA线程模式。可以在注册表的 HKEY_CLASSES_ROOT\CLSID\{Class ID of the COM component} \InProcServer32 下查看到该COM的线程模式。如果该值是Apartment,则说明该COM只能以STA模式运行。其他的值有Free(MTA),Both(STA+MTA),Single(只能在一个单一的线程中执行)。
其他情况下,我们应该使用MTA的线程,虽然需要我们费心线程间资源的同步问题。


示例:
我现在想在一个windows form的程序中实现从某个word文档复制图片并保存的方案。
具体是:打开word文档,将图片信息复制到粘贴板中,然后从粘贴板中取得图片信息,再保存到本地目录中。

说明:(本来是放在代码下面的,无奈POST之后就被代码挡住不显示了 emsad.gif
如果在某个按钮的事件中,直接调用该方法,那么界面将变得没有响应。所以我们需要考虑使用多线程来解决这个问题。Thread t = new Thread(new TheardStart(CopyImages); t.Start();
如果是这样,则程序会发生错误.。要么显示出现异常,要么没异常但是Clipboard为空,取不到任何数据!为什么呢?
因为Word.Application 是Automation并且STA-Based,不能在没有指定ThreadApartment的线程中被调用。所以导致了各种错误,所以需要在t.Start();前面加上t.Apartment = ApartmentState.STA;这样就完全正常了。
对于MTA的多线程我们就见的比较多了,不再举例了。

另外一点不明白,我监视任务管理器发现,我在执行Thread t = new Thread(new TheardStart(CopyImages);t.Apartment = ApartmentState.STA; t.Start();之后该程序的进程中线程数从3个增加到6个,如果创建的是MTA的线程则只增加1。我的理解是STA线程为需要维护内部隐藏的窗口类和消息队列而增加的。

下面是实现方法:
ContractedBlock.gif ExpandedBlockStart.gif
 1None.gifprivate void CopyImages()
 2ExpandedBlockStart.gifContractedBlock.gif        dot.gif{
 3InBlock.gif            Word.Application app = null;
 4InBlock.gif            Word.Document doc = null;
 5InBlock.gif            
 6InBlock.gif            app = new ApplicationClass();
 7InBlock.gif            
 8InBlock.gif            try
 9ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
10InBlock.gif                object fileName = @"E:\A.doc";
11InBlock.gif                doc = app.Documents.Open(ref fileName,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,
12InBlock.gif                    ref missing,ref missing,ref missing,ref missing,ref missing,ref missing);
13InBlock.gif
14InBlock.gif                int count = doc.InlineShapes.Count;
15InBlock.gif                for(int i=1;i<=count;i++)
16ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
17InBlock.gif                    doc.InlineShapes[i].Range.Copy();
18InBlock.gif                    
19InBlock.gif                    if (Clipboard.GetDataObject() != null
20ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif
21InBlock.gif                        IDataObject data = Clipboard.GetDataObject(); 
22InBlock.gif
23InBlock.gif                        if (data.GetDataPresent(DataFormats.Bitmap)) 
24ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif
25InBlock.gif                            Image image = (Image)data.GetData(DataFormats.Bitmap,true); 
26InBlock.gif                            image.Save("E:\\" + i.ToString() + ".jpg",System.Drawing.Imaging.ImageFormat.Jpeg); 
27ExpandedSubBlockEnd.gif                        }
 
28InBlock.gif                        else 
29ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif
30InBlock.gif                            lst_Items.Items.Add(doc.Name + ";无正确图片数据");
31ExpandedSubBlockEnd.gif                        }
 
32ExpandedSubBlockEnd.gif                    }
 
33InBlock.gif                    else 
34ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif
35InBlock.gif                        lst_Items.Items.Add(doc.Name + ";粘贴板为空");
36ExpandedSubBlockEnd.gif                    }
 
37ExpandedSubBlockEnd.gif                }

38InBlock.gif                
39ExpandedSubBlockEnd.gif            }

40InBlock.gif            catch(Exception ex)
41ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
42InBlock.gif                lst_Items.Items.Add(doc.Name + "发生错误;" + ex.Message);
43ExpandedSubBlockEnd.gif            }

44InBlock.gif            finally
45ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
46InBlock.gif                if (doc != null)
47InBlock.gif                    doc.Close(ref missing,ref missing,ref missing);
48InBlock.gif                if (app != null)
49InBlock.gif                    app.Quit(ref missing,ref missing,ref missing);
50ExpandedSubBlockEnd.gif            }


转载于:https://www.cnblogs.com/mancini/archive/2005/11/16/277929.html

<think>嗯,用户提到了CVI报错,提示对话框无法在MTA中显示。首先,我需要理解CVI和MTA分别是什么。CVI可能是指LabWindows/CVI,这是National Instruments的一个开发环境,用于测试和测量应用的C语言编程。而MTA可能是指多线程公寓(Multithreaded Apartment),这在COM(Component Object Model)编程中涉及到线程模型的术语。 接下来,用户的问题是在使用CVI时遇到了对话框无法在MTA线程中显示的报错。这可能涉及到线程模型的问题,因为对话框通常是基于消息泵的,而MTA线程可能不支持这种消息循环。需要确认对话框是否在主线程(STA,单线程公寓)中创建,因为UI元素通常需要在STA线程中运行。 可能的解决方案包括检查线程模型设置,确保对话框在STA线程中创建,或者调整COM初始化方式。此外,可能需要在创建窗口前正确初始化COM库,或者使用CVI提供的相关函数来处理多线程问题。还需要考虑是否有代码在非UI线程中操作UI元素,这可能导致问题。建议用户检查代码中线程的使用情况,确保所有UI操作都在主线程执行,必要时使用线程同步机制。</think>关于CVI报错"Dialog无法显示在MTA"的问题,以下是分步解析与解决方案: 1. **理解核心概念** - **CVI**:指LabWindows/CVI开发环境 - **MTA**:多线程公寓(Multithreaded Apartment),COM组件的线程模型 - **STA**:单线程公寓(Single-Threaded Apartment),UI线程常用模型 2. **问题根源** $$ \text{UI操作} \notin \text{MTA线程} $$ 对话框等GUI组件必须运行在STA线程,而当前代码尝试在MTA线程创建窗口。 3. **验证步骤** - 检查项目设置: ```c // 确保在工程设置中启用STA SetComApartmentType(STA); ``` - 查看线程初始化代码: ```c CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // 正确初始化 ``` 4. **解决方案** - **方法1:强制主线程STA** ```c int __stdcall WinMain(...) { CmtSetUICallback(..., RunUserInterface); } ``` - **方法2:显式创建消息泵** ```c MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } ``` - **方法3:使用CVI线程管理** ```c CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, STA_ThreadFunction, NULL, &threadID); ``` 5. **常见错误排查点** - 检查第三方控件是否兼容STA - 验证COM对象初始化参数 - 确保未混合使用`CoInitialize`和`CoInitializeEx` - 使用调试器检查线程调用堆栈 6. **预防措施** - 在项目初期设置: $$ \text{Project} \rightarrow \text{Build Options} \rightarrow \text{Runtime} \rightarrow \text{Threading Model} = \text{STA} $$ - 遵循CVI UI线程规范 - 对跨线程操作使用`PostDeferredCallToThread` 建议通过CVI自带的Thread Checker工具进一步分析线程交互,若问题持续,可提供具体错误代码片段以便进一步诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值