【问题标题】:Are parameters Thread Safe?参数是线程安全的吗?
【发布时间】:2017-07-07 14:58:35
【问题描述】:

我已经阅读了许多关于这个主题的帖子,但我仍然有点模糊 C# 在从多个线程调用时如何处理方法中的参数。

我有一系列实用方法需要从大约 60 多个线程中调用。这是一个每天为大约 20,000-30,000 名患者下载患者数据的过程。大多数情况下,这些方法看起来像这样。

Public Static SomeClass { public static string StringToSQLBool(string s) { if (s.Trim() == "") { return "Null"; } else { if (s.ToLower() == "true") { return "1"; } { return "0"; } } } public static string DateToSQLAnsiStr(string ADate) { try { if (ADate.Trim() != "") { DateTime d = Convert.ToDateTime(ADate); return "{d '" + d.Year.ToString() + "-" + d.Month.ToString().PadLeft(2, '0') + "-" + d.Day.ToString().PadLeft(2, '0') + "'}"; } else { return "Null"; } } catch { return "Null"; } } }

据我了解,只要在方法中使用的参数对调用线程来说是单数的,那么它就被认为是安全的。

这些在没有锁定的情况下是线程安全的吗?

【问题讨论】:

  • 它们是字符串。字符串是不可变的。是的,只要作为参数传递的引用类型仅在该线程内访问,那么就不需要锁定等。如果您将一个类实例传递给两个单独的线程然后开始尝试操作相同的线程,这只是一个问题变量。
  • 您只展示了单线程代码,因此我们无法评论您未展示的操作的安全性
  • 您的代码似乎根本错误。这意味着您构建一串单独的部分来获取 SQL 查询,例如 var sqlQuery = "update tableName set column1 = '" + text + "' where id = " + 1; 这种构建 SQL 查询的方式有很多问题,例如 SQL 注入 (stackoverflow.com/questions/601300),您必须处理不同的类型对自己(就像你正在做的那样)和他人的价值。你应该总是使用参数化查询!!!
  • @RandRandom,这不是我要做的。
  • 请问你的代码是干什么用的?

标签: c# multithreading parameters thread-safety


【解决方案1】:

TL;DR - 根据提问的方式,是的。参数是线程安全的,因为两个线程可以同时调用同一个方法并传递不同的参数。


从不同线程对方法的每次调用都有自己的堆栈。传递给方法的值类型存储在堆栈中。传递给方法的引用类型的指针存储在堆栈中。无论哪种方式,它都在堆栈上。

因为每个线程都有自己的堆栈,所以从不同线程对方法的多次调用不会“覆盖”彼此的参数。

据我了解,只要在方法中使用的参数对调用线程来说是单数的,那么它就被认为是安全的。

人们倾向于像律师一样将这样的陈述分开(特别是因为它涉及听起来像医疗记录的内容。)你的理解是正确的。

我并不是说像律师那样分清问题是错误的。细节很重要。但是你问的很清楚,所以我明白你的意思。

我该怎么说才不会显得有些傲慢,因为您可能是一位非常有经验的程序员,而这恰好是您第一次专门使用 .NET 处理多线程。请小心。想到医疗记录发给错误的人,索赔被拒绝,或者有人因为线程错误而意外接受化疗或性别重新分配,我感到震惊。我认为在这种情况下,社区应该非常积极地帮助您解决所有多线程问题。

【讨论】:

  • 谢谢斯科特。是的,我已经开发了 30 多年。但只有几个月的 C# 。我的任务是将以前用另一种语言编写的多线程应用程序迁移到 C#。我发现 C# 很古怪,并且对象模型设计有点时髦。可能是由于 MS 试图使其“易于”使用。我已经编写了几个线程应用程序,只是不是在 C# 中。所以不用担心,没有任何数据会分配给错误的患者。 ;)
【解决方案2】:

当尝试跨线程操纵(或在一个中操纵并在另一个中访问)相同的对象时,线程是一个问题。访问对象的“名称”无关紧要。

使用术语“变量”来讨论类成员是一种不太理想的方式,尤其是在上下文中,指代字段。这就是这里的关键区别:局部变量,包括参数,永远不能被两个线程同时访问1

逐字回答这个问题:“参数总是线程安全的”,尽管 它们评估的对象可能不是。

但是,在示例代码中,使用了不可变对象2

String + 操作符返回一个 new 字符串,是两者的连接,并且正是这个新的 String 结果被重新分配给本地(参数)变量。同样的逻辑也适用于 DateTime。

因此,发布的代码没有线程问题;因为无论局部变量或参数如何,都没有对相同对象的共享操作(或操作和访问)。


1 对闭包绑定变量(包括参数)的访问通常必须被视为线程上下文中的字段访问。这是因为 C# 编译器在后台合成/创建一个隐藏对象,然后对其进行操作以存储关闭状态。

2 如果一个对象在创建后不能被操作,它被认为是不可变类型并且本质上是线程安全的。字符串属于这一类。 (不可变对象的线程安全只有在对象完全构造后才能保证。)

【讨论】:

    【解决方案3】:

    标题中问题的答案是“也许;这取决于他们的类型。”

    • 值类型:是
    • 参考类型:
      • 不可变对象:是的
      • 普通对象:无

    【讨论】:

      猜你喜欢
      • 2023-04-07
      • 1970-01-01
      • 2013-09-04
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 2015-04-18
      • 2011-10-07
      相关资源
      最近更新 更多