zoukankan      html  css  js  c++  java
  • STA和MTA线程模式的区别

    文章来源: http://blog.csdn.net/fragno/article/details/7982044

    STA:   Single-Thread   Apartment,   中文叫单线程套间。就是在COM库初始化的时候创建一个内存结构,然后让它和调用CoInitialize的线程相关联。这个内存结构针对每个线程都会有一个。支持STA的COM对象只能在创建它的线程里被使用,其它线程如果再创建它就会失败。   

        MTA:   Mutil-Thread   Apartment,中文叫多线程套间。COM库在进程中创建一个内存结构,这个内存结构在整个进程中只能有一个,然后让它和调用CoInitializeEx的线程相关联。支持MTA的COM对象可以在任意线程里被使用。多有针对它的调用都会被封装成为消息。

        其实STA和MTA是COM规定的一套线程模型,用于保障多线程情况下你的组件代码的同步。比如说有一个COM对象它内部有一个静态变量   gHello,那么这个对象无论生成多少实例对于gHello在内存中只能有一份,那么如果有两个不同的实例在两个线程里面同时去读写它,就有可能出错,所以就要就要有种机制进行同步保护,STA或者MTA就是这种机制。

    进程相对于一个小城镇,线程相当于这个城镇里的居民,STA(单线程套间)相当于居民房,是私有的,MTA(多线程套间)相当于旅馆,是公用的,Com对象相当于居民房或旅馆里的物品.接下去就好理解了,一个小城镇(进程)里可以有很多很多的(居民)线程,这个城镇(进程)只有一间旅馆(MTA),但可以有很多很多的居民房(STA).只有居民(线程)进入了房间(居民房或旅馆,STA或MTA)以后才能使用该房间里的物品(COM对象),居民房(STA)里的物品(COM对象)只能供这间房子的主人(创建该STA的线程)使用,其它居民(线程)不能访问.同样,只有入住到旅馆(MTA)里的居民(线程,可以有多个)才可以访问到旅馆(MTA)里的物品(com对象),但因为是公用的,所以要合理的分配(同步)才能不会产生混乱.


    .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_ROOTCLSID{Class ID of the COM component} InProcServer32 下查看到该COM的线程模式。如果该值是Apartment,则说明该COM只能以STA模式运行。其他的值有Free(MTA),Both(STA+MTA),Single(只能在一个单一的线程中执行)。
    其他情况下,我们应该使用MTA的线程,虽然需要我们费心线程间资源的同步问题。


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

    说明:(本来是放在代码下面的,无奈POST之后就被代码挡住不显示了)
    如果在某个按钮的事件中,直接调用该方法,那么界面将变得没有响应。所以我们需要考虑使用多线程来解决这个问题。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线程为需要维护内部隐藏的窗口类和消息队列而增加的。

    下面是实现方法: 
    1private void CopyImages()
    2        {
    3            Word.Application app = null;
    4            Word.Document doc = null;
    5            
    6            app = new ApplicationClass();
    7            
    8            try
    9            {
    10                object fileName = @"E:A.doc";
    11                doc = app.Documents.Open(ref fileName,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,ref missing,
    12                    ref missing,ref missing,ref missing,ref missing,ref missing,ref missing);
    13
    14                int count = doc.InlineShapes.Count;
    15                for(int i=1;i<=count;i++)
    16                {
    17                    doc.InlineShapes[i].Range.Copy();
    18                    
    19                    if (Clipboard.GetDataObject() != null) 
    20                    { 
    21                        IDataObject data = Clipboard.GetDataObject(); 
    22
    23                        if (data.GetDataPresent(DataFormats.Bitmap)) 
    24                        { 
    25                            Image image = (Image)data.GetData(DataFormats.Bitmap,true); 
    26                            image.Save("E:\" + i.ToString() + ".jpg",System.Drawing.Imaging.ImageFormat.Jpeg); 
    27                        } 
    28                        else 
    29                        { 
    30                            lst_Items.Items.Add(doc.Name + ";无正确图片数据");
    31                        } 
    32                    } 
    33                    else 
    34                    { 
    35                        lst_Items.Items.Add(doc.Name + ";粘贴板为空");
    36                    } 
    37                }
    38                
    39            }
    40            catch(Exception ex)
    41            {
    42                lst_Items.Items.Add(doc.Name + "发生错误;" + ex.Message);
    43            }
    44            finally
    45            {
    46                if (doc != null)
    47                    doc.Close(ref missing,ref missing,ref missing);
    48                if (app != null)
    49                    app.Quit(ref missing,ref missing,ref missing);
    50            }

  • 相关阅读:
    dpkg 删除 百度网盘 程序
    ubuntu 安装go
    解决 swap file “*.swp”already exists!问题
    ROS Topic 常用指令
    正交概念
    vim 永久显示行号 & 临时显示行号
    awk、grep、sed
    Keil中使用Astyel进行C语言的格式化
    红黑树学习
    802.11 对于multicast 和 broadcast的处理
  • 原文地址:https://www.cnblogs.com/PeterPan-luo/p/4014262.html
Copyright © 2011-2022 走看看