方法参数是否安全?

时间:2013-01-08 22:48:29

标签: c#

public void Remove(T item)
{
    locker.EnterWriteLock();        
    try
    {
        list.Remove(item);
    }
}

以上是实例类的方法。假设实例是myObject。 关于上述片段,我的问题是:

线程一调用myObject.Remove(A) 线程1执行locker.EnterWriteLock()

线程两次调用myObject.Remove(B)

线程1进入try块并执行list.Remove()

此时item的价值是多少?即将{A}或B作为参数调用list.Remove()

6 个答案:

答案 0 :(得分:3)

每个线程都有自己的调用堆栈,方法参数存储在该堆栈中。线程之间不共享堆栈。

在第一个线程的堆栈中,有一行表示正在调用Remove并且包含“A”或对“A”的引用(取决于它是值还是引用类型)。

当线程2进入方法时,它具有自己的调用堆栈(线程1的堆栈在线程2运行时未使用),其中有一行指示Remove的项目“B”的开始。然后该线程被挂起,它的调用堆栈未被使用,我们返回到线程1,其中项“A”是调用堆栈上的内容。

在未来的某个时刻,线程2将被重新激活,并且在它的调用堆栈上将有“B”项。

答案 1 :(得分:1)

方法参数在调用方法的线程的堆栈上分配。因此,每个线程都有自己的参数,它们不会相互影响。

答案 2 :(得分:0)

我怀疑你应该锁定的是list变量。你在它上面调用Remove方法,如果这个list变量是某种非线程安全的类型,例如List<T>,你可能会遇到麻烦,如果这个方法同时从myObject的同一个实例上的多个线程(这是您的list字段所在的位置)。就方法的论点而言,在方法的上下文中很难谈论它们的任何线程安全性。

答案 3 :(得分:0)

.Net不对参数提供任何继承锁定。但是,list.Remove(item)不会修改item(假设它是标准的System.CollectionsSystem.Collections.Generic实现),并且使用不同的参数调用相同的方法两次会创建{{1}的两个副本(每个方法调用一个),而不是一个。

相反,我会锁定列表,因为大多数类的实例方法都不能保证是线程安全的。

答案 4 :(得分:0)

线程2将在locker.EnterWriteLock();等待线程1执行locker.ExitWriteLock();

因此线程2在线程1调用list

之前无法访问locker.ExitWriteLock();

如果你担心参数item,请确保它通过堆栈并且每个线程都有自己的一个,所以item实际上不能被另一个线程“替换”...

所以答案是:如果线程1在线程2之前调用locker.EnterWriteLock();A将在B之前删除。

答案 5 :(得分:0)

item的值将是A参数的值。

只有在行locker.ExitWriteLock执行后,该块才可用于第一个线程。