C# 静态方法是线程安全的吗

C# 静态方法是线程安全的吗,c#,asp.net,static,C#,Asp.net,Static,我有一个静态计时器类,任何网页都会调用它来计算每个页面的构建时间 我的问题是静态类是线程安全的吗?在我的示例中,并发用户会导致我的启动和停止时间出现问题吗?e、 g不同的线程覆盖我的开始和停止值 public static class Timer { private static DateTime _startTime; private static DateTime _stopTime; /// <summary> /// Gets the

我有一个静态计时器类,任何网页都会调用它来计算每个页面的构建时间

我的问题是静态类是线程安全的吗?在我的示例中,并发用户会导致我的启动和停止时间出现问题吗?e、 g不同的线程覆盖我的开始和停止值

public static class Timer
{
    private static DateTime _startTime;
    private static DateTime _stopTime;    

    /// <summary>
    /// Gets the amount of time taken in milliseconds
    /// </summary>
    /// <returns></returns>
    public static decimal Duration()
    {
        TimeSpan duration =  _stopTime - _startTime;
        return duration.Milliseconds;
    }

    public static void Start()
    {
        _startTime = DateTime.Now;
    }

    public static void Stop()
    {
        _stopTime = DateTime.Now;
    }
}
公共静态类计时器
{
私有静态日期时间_startTime;
私有静态日期时间_stopTime;
/// 
///获取以毫秒为单位的时间量
/// 
/// 
公共静态十进制持续时间()
{
时间跨度持续时间=\u停止时间-\u开始时间;
返回持续时间(毫秒);
}
公共静态void Start()
{
_startTime=DateTime.Now;
}
公共静态无效停止()
{
_stopTime=DateTime.Now;
}
}
这个类应该是非静态类吗


(该类将从asp.net母版页调用。)

是的,没错,该类上的静态成员/访问器将导致不同用户覆盖它们

这就是为什么有实例和非静态成员。

静态方法本质上不是线程安全的。CLR对它们的处理与实例方法没有什么不同。不同的是,人们通常应该尝试使它们线程安全。(我想不出任何一个.NET BCL静态方法是线程安全的。)实例方法通常不是线程安全的,因为典型的模式是创建一个对象并从一个线程重复使用它,如果必须从多个线程使用它,所涉及的协调包括确保安全使用该对象。在很多情况下,协调代码比对象本身更适合这样做。(通常,您希望使整个操作序列有效地原子化——这是在对象内无法完成的。)

您的
Timer
类绝对不是线程安全的:两个线程可以轻松地践踏彼此的数据,并且在计算持续时间时,没有什么可以阻止线程使用“过时”数据


改用这个类——这就是它的用途。诚然,如果您想从多个线程中使用一个实例,您需要采取正常的步骤来确保安全性,但通常情况下您会处于更好的位置。诚然,
秒表
也远远不够完美——更多细节请参见下文和评论——但它至少是这款手表的设计目的。(谁知道呢,它可能会在某个时间被修复…

您的计时器类肯定不是线程安全的。您应该创建一个普通类,并在每次需要测量时间时实例化它:

Timer timer = new Timer();

timer.Start();
//...
timer.Stop();

decimal duration = timer.Duration();
更妙的是,有一个内置的.NET类可以做到这一点:

Stopwatch sw = Stopwatch.StartNew();

sw.Stop();

TimeSpan duration = sw.Elapsed;

这里有一个很好的讨论,它更多地关注了为什么您的示例不是线程安全的机制和原因

总之,首先,您的静态变量将被共享。如果您可以使它们成为局部变量,即使它们是静态方法的局部变量,它们仍然会获得自己的堆栈框架,因此是线程安全的。此外,如果您以其他方式保护静态变量(即,锁和/或本线程中其他人提到的其他多线程编程技术),您还可以使示例静态类线程安全


其次,因为您的示例不接受您修改的外部变量实例或其状态可能会被另一个线程操作的外部变量实例,所以您的示例在这方面也是线程安全的。

MSDN:“虽然类的实例包含类的所有实例字段的单独副本,但每个静态字段只有一个副本。”相关文章-&如果您将Stopwatch类与多个内核或多个处理器一起使用,它本身也有问题。秒表使用滴答计数来确定持续时间,并且由于BIOS中的错误,秒表可以在一个内核上启动,在另一个内核上停止,此时两个内核上的滴答计数不同步。我在Vss2Git开源应用程序中发现了这一点,该应用程序使用秒表,有时试图给出一个负的持续时间。Fpr更多信息见@SimonTewsi:是的,我以前听说过。将编辑一个链接到答案中。@JonSkeet,你能解释一下“实例方法通常不是线程安全的,因为典型的模式是创建一个对象并从一个线程重复使用它”。这是令人困惑的,因为当我听到这个实例时,我自动地认为线程是安全的。你上面所说的和Guffa在这篇文章中所说的意思相同吗?我想确保我理解你在声明中所说的话。谢谢。@Fractal:是的,Guffa的说法和我刚才说的差不多。非常好的信息,这正是我来这里的目的:如果静态方法只使用局部变量,它是线程安全的吗?干杯,是的。但是请记住,它需要是方法的局部变量,而不是静态类变量。(我认为有时类变量被称为局部变量,但我可能弄错了。)既然您说“只使用局部变量”,我也认为这意味着您没有将传入参数的引用分配给局部变量。