【问题标题】:Ensuring Thread-Safety On Static Methods In C#确保 C# 中静态方法的线程安全
【发布时间】:2012-09-12 16:24:31
【问题描述】:

我目前在静态类/方法中有一些代码,但我想检查它是否是线程安全的。从我读过的内容来看,我认为这应该没问题,但在我的脑海里有些东西在说它可能不是。我的网页的数据处理阶段使用外部 Web 服务来创建订单记录,这可能会很慢:可能需要 30-40 秒,也可能需要 5 或 10 分钟(这不在我的掌控之中)所以我要开除将页面返回给用户,然后启动一个新线程,然后在处理完成后向用户发送电子邮件。这目前在静态类/方法中。如果我的所有对象都是在特定方法中创建的(除了系统默认值,这很常见),那么该方法应该是线程安全的,不是吗。所以,例如,如果我有

public static class ProcessOrder()
{
    public static int GetOrderMaxSize()
    {
        return (....gets and parses ConfigurationManager.AppSettings["MaxOrderSize"]...);
    }

    public static bool CreateOrder(Order order)
    {
        XmlDocument xmlDoc = GetOrderXML(order);
        bool check = false;
        using (CreateOrderXML.Create xmlCo = new CreateOrderXML.Create())
        {
            xmlCo.Timeout = 60000;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

            string xmlString = "";
            using (StringWriter stringWriter = new StringWriter())
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
                {
                    xmlDoc.WriteTo(xmlWriter);
                    xmlWriter.Flush();
                    xmlString = stringWriter.GetStringBuilder().ToString();
                }
            }

            byte[] bXMLOrder = encoding.GetBytes(xmlString);
            byte[] breturnMessage;

            check = xmlCo.Create(bXMLOrder, out breturnMessage);
            .... do something with return message
        }
        return check;
    }

    private static XmlDocument GetOrderXML(Order order)
    {
        ... creates an XML object for the order
    }
}

(CreateOrderXML 是对 Web 服务 URL/方法的服务引用)是否是线程安全的,尤其是对于长时间运行(主要在 xmlCo.Create(....) 阶段)并发线程?我知道如果我开始放入类成员然后在方法中使用它们,这肯定会引入不同线程覆盖值的问题,但只要在方法中创建对象,它们应该没问题,不应该他们呢?

【问题讨论】:

    标签: c# .net multithreading static thread-safety


    【解决方案1】:

    您似乎没有访问那里的任何共享数据;您正在请求远程资源,并在每次执行此方法时构建一组唯一的数据。那里不需要同步。

    这里方法的每次执行都会创建局部变量 - 它是自己的副本。所以什么都不会被共享。

    【讨论】:

    • 是的,我故意只在类本身中使用“系统范围的默认”变量,并且我通过方法传递了处理可能特定于用户/会话所需的所有内容参数。但我的脑后仍然有警告蜂鸣器响起,希望它们只是“健康的偏执狂”。
    • 对我来说听起来像是健康的偏执狂!
    【解决方案2】:

    如果您的静态方法不访问任何静态(类)数据,它应该是线程安全的。唯一可能的争论点是它可能使用的外部资源(例如文件或其他系统资源)以及传入的数据。只有您知道这种使用的上下文。

    可以使用lock 或其他原语对可能存在争用的内容进行序列化。不要忘记以相同的顺序序列化资源,以免死锁。如果您有一种使用资源 A 和 B 的方法:

    lock( latch_a )
    {
       process(object_a) ;
       lock ( latch_b )
       {
         process(object_a,object_b) ;
       }
    }
    

    还有另一种相反的方法:

    lock( latch_b )
    {
       process(object_b) ;
       lock ( latch_a )
       {
         process(object_a,object_b) ;
       }
    }
    

    在某些时候,你的两个线程会死锁,当它们中的每一个都需要一个资源时,另一个线程才可以放弃对所述资源的访问。

    编辑注意: 有关详细信息,请参阅 lock 语句的 C# 文档。通常,锁定对象代表(并且可能是)正在序列化的共享资源访问。一种常见的模式是执行以下操作:

    class Widget
    {
       private static readonly object X = new object() ;
    
       public void Foo()
       {
         lock(X)
         {
           // Do work using shared resource
         }
         return ;
       }
    
    }
    

    【讨论】:

    • latch_a和latch_b对象是不是需要创建一次,然后传入到每次调用静态方法中?
    • @Doug:查看我修改后的答案。
    猜你喜欢
    • 2012-12-04
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    相关资源
    最近更新 更多