C# 线程安全和局部变量

C# 线程安全和局部变量,c#,C#,如果我有这样一个局部变量: Increment() { int i = getFromDb(); // get count for a customer from db }; 这是一个递增的实例类(每次客户(实例对象)购买时),这个变量是线程安全的吗?我听说局部变量是线程安全的,因为每个线程都有自己的堆栈,等等 另外,我认为这个变量是共享状态,对吗?我在thinking dept中缺少的是,这个变量将与不同的客户对象(例如John、Paul等)一起工作,因此线程是安全的,但这是有缺陷

如果我有这样一个局部变量:

Increment()
{
    int i = getFromDb(); // get count for a customer from db 
};
这是一个递增的实例类(每次客户(实例对象)购买时),这个变量是线程安全的吗?我听说局部变量是线程安全的,因为每个线程都有自己的堆栈,等等

另外,我认为这个变量是共享状态,对吗?我在thinking dept中缺少的是,这个变量将与不同的客户对象(例如John、Paul等)一起工作,因此线程是安全的,但这是有缺陷的想法,并且在并发编程方面有点缺乏经验。这听起来很幼稚,但我在并发编码方面没有像一般同步编码那样的丰富经验

编辑:另外,函数调用getFromDb()不是问题的一部分,我不希望任何人猜测它的线程安全性,因为它只是一个调用,用于指示值是从从db获取数据的函数分配的。:)


编辑2:另外,getFromDb的线程安全性是有保证的,因为它只执行读取操作。

您的语句有两个独立的部分—函数调用和赋值

赋值是线程安全的,因为变量是局部变量。此方法的每次不同调用都将获得其自身版本的局部变量,每个局部变量存储在内存中不同位置的不同堆栈帧中


对getFromDb()的调用可能是线程安全的,也可能不是线程安全的,这取决于它的实现。

只要变量是方法的本地变量,它就是线程安全的。如果它是一个静态变量,那么默认情况下就不会是静态变量

class Example
{
  static int var1; //not thread-safe

  public void Method1()
   { int var2; //thread-safe
   }
}

i
声明为局部(方法)变量,因此它通常只存在于
Increment()
的堆栈框架中-因此是的,
i
是线程安全的。。。(尽管我不能对
getFromDb
发表评论)

除非:

  • Increment
    是一个迭代器块(即使用
    yield return
    yield break
  • i
    用于匿名方法(
    delegate{i=i+1;}
    )或lambda(
    foo=>{i=i+foo;}
在以上两种情况下,有些情况下它可以暴露在堆栈之外,但我怀疑你是否这样做了


请注意,字段(类上的变量)不是线程安全的,因为它们很少暴露给其他线程。这在
静态
字段中更为明显,因为所有线程自动共享同一字段(线程静态字段除外).

虽然您的int i是线程安全的,但您的整个案例可能不是线程安全的。正如您所说,您的int i是线程安全的,因为每个线程都有自己的堆栈跟踪,因此每个线程都有自己的i。但是,您的线程都共享同一个数据库,因此您的数据库访问不是线程安全的。您需要正确同步对数据库访问进行ronize,以确保每个线程只在正确的时刻看到数据库


与并发和多线程处理一样,如果只读取信息,则不需要在数据库上同步。只要两个线程尝试从数据库读取/写入同一组信息,就需要同步。

我将是“线程安全的”正如您所建议的,每个线程在堆栈上都有自己的i副本。真正的问题是getFromDb()的内容是否是线程安全的?

i是一个局部变量,因此它不是共享状态

如果您的getFromDb()正在读取oracle序列或sql server autoincrement字段,则db负责同步(在大多数情况下,不包括复制/分布式数据库),因此您可能可以安全地将结果返回给任何调用线程。也就是说,db保证每个getFromDb()调用将获得不同的值


线程安全通常是一项小工作——更改变量的类型很少能保证线程安全,因为这取决于线程访问数据的方式。通过修改算法,使其使用一个所有使用者都同步的队列,而不是试图协调一系列数据,可以省去一些麻烦锁定/监视。如果可能的话,最好是使算法无锁。

i在语法上是线程安全的。但是当您分配实例变量的值时,实例方法将值返回给i,然后共享数据由多个线程操作。

+1以确保完整性(讨论anon方法和迭代器块。静态类和线程安全性是最容易掌握的概念,就个人而言。:)IMHO,重要的是要澄清,即使在列出的异常中,局部变量对于方法的每个调用仍然是唯一的。也就是说,尽管它们可以在方法的上下文之外访问,甚至可能以非线程安全的方式访问,但相对于不同cal上下文中的相同局部变量,它们仍然是线程安全的我用同样的方法。