【问题标题】:C# Thread safe codeC# 线程安全代码
【发布时间】:2015-04-24 14:30:48
【问题描述】:

这段代码线程安全吗?

DoStuff 使用 Task 在新线程中调用。

Task.Factory.StartNew(() => DoStuff());


private void DoStuff()
{
    List<SalesRecord> salesRecords = new List<SalesRecord>();
    SalesRecord salesRecord1 = new SalesRecord {Amount = 10.0, Sales = 1};
    SalesRecord salesRecord2 = new SalesRecord {Amount = 15.0, Sales = 1};
    SalesRecord salesRecord3 = new SalesRecord {Amount = 1.0, Sales = 2};
    salesRecords.Add(salesRecord1);
    salesRecords.Add(salesRecord2);
    salesRecords.Add(salesRecord3);
    SalesRecord result = Util.SumSales(salesRecords);
}

只用于存储数据的结构:

public struct SalesRecord
{
    public uint Sales;
    public double Amount;
}

东西

public static class Util
{
    public static SalesRecord SumSales(List<SalesRecord> records)
    {
        SalesRecord result = new SalesRecord();

        result.Amount = records.FindAll(record => (record.Sales == 1)).Sum(record => record.Amount);
        result.Sales = 1;
        return result;
    }
}

【问题讨论】:

  • 我实际上并没有看到任何多线程正在发生,所以我从您提供的代码中猜测是的,它是线程安全的。除非你在不同线程之间访问东西,否则这段代码应该不是问题。
  • 第二句。 DoStuff 是使用 Task 调用的。 @JoshL。
  • 我看不到你真正调用 DoStuff 的地方 - 很高兴看到它用于做出有根据的决定。
  • @user1766169 只要一切都在同一个线程中完成,这并不重要。这是单线程代码。
  • 我没有看到static 属性并且您只使用局部变量进行操作,在DoStuff 之外不可能出现多线程问题。这使得DoStuff 线程安全。

标签: c# multithreading


【解决方案1】:

这段代码线程安全吗?

是的,是的。此代码不使用任何共享状态。根据定义,不使用任何共享状态的代码是线程安全的。

您可以在任意数量的线程中同时调用DoStuff,没有任何问题。尽管如此,DoStuff 方法并不是很有用。

【讨论】:

  • 如果返回 'salesRecords','DoStuff' 仍然是线程安全的吗? @SriramSakthivel
  • @user1766169 是的,会的。但这仍然没有用。仅当您从两个线程访问相同的实例/静态成员时,线程安全才是一个问题。但是您的代码没有,因此它是线程安全的。
【解决方案2】:

您的代码看起来不错。即使 DoStuff 是通过 Task 启动的,我也没有在您的代码中看到您处理类变量的任何地方,它们都是局部变量。

参考: C# : What if a static method is called from multiple threads?

【讨论】:

  • @PeterSchneider 仅当它是类/共享状态变量时,它不是。它是线程的局部变量。如果 OP 要再次通过任务启动另一个 DoStuff(),则该类将有另一个本地列表。
  • @PeterSchneider 错错了。它是从单个线程调用的,在它定义的方法的本地实例上。没有其他线程可以访问这个实例
  • 正如我在另一条评论中所说,我没有仔细阅读该方法。 (但作为一个借口,我同意@SiriamSa DoStuff() 没有做任何误导读者的事情。事实上,可能不需要为它生成代码,以便容易显示线程安全。)跨度>
【解决方案3】:

发布给那些试图弄清楚为什么即使使用静态方法也是线程安全的人

在这种特殊情况下,对 Util.SumSales(salesRecords) 的访问是线程安全的,因为它是线程本地方法(调用此方法的线程将其自己的数据副本提供给该方法并在该线程中访问数据是调用它的线程独有的)。

当你调用以下代码时:

Task.Factory.StartNew(() => DoStuff());

您分配了一个新线程来处理 DoStuff()。 DoStuff 中发生的所有事情(除非您引入可以在其外部进行操作的变量)都是该新线程独有的。

我假设你会用你从 DoStuff() 得到的东西做更多的事情。在这种情况下,您应该将结果存储在Concurrent Collections

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 2015-11-03
    相关资源
    最近更新 更多