2010-08-06 40 views
1

我有这样在ASP.net中使用静态方法进行安全验证是不明智的?

public static string DoSomethingToString(string UntrustedString) 
{ 
//parse format and change string here. 
return newString. 
} 

一个静态方法,因为我知道,多次调用:

static int myInt=0; 
public static int AddNumber() 
{ 
lock(someObject) 
{ 
myInt++; 
return myInt;  
} 
} 

会返回一个数量不断增加(即页面之间共享),我不知道在DoSomethingToString()中如何处理变量的局部变量;

我想了解一个静态方法可以安全/不安全地在ASP.net中使用的条件,只是为了让我的多线程大脑停留在这个主题上。

UPDATE:

大部分的讨论一直围绕价值类型。我如何知道何时可以安全地调用改变我的引用类型的方法(显式或隐式)?查看MSDN文档是否足够,并且只使用表示“threadSafe”的方法?

一个例子,如果我所谓的隐式改变是使用String.Split(),因为它是同一类的一部分。我认为可能会分担一些安全特征,并且不需要担心/尽职调查。 (?)

我打电话给一个明确的变化(因为缺乏一个更好的词)现在调用另一个方法来做工作......可以是静态的或实例类。我认为需要做更多的背景/研究工作来确保每个对象和方法都是ThreadSafe。

为了讨论起见假设我有这个签名的方法:

ValidateStringAndContext(string untrustedString, Object myCustomUserContext) 

,它有它引用了以下对象

public SecurityChecker 
{ 
public static object CheckSecurityStatic(string DirtyData) 
{ 
//do string.split 
//maybe call a database, see if it's a token replay 
// 

//OR - alternate implementation 
SecurityChecker sc = new SecurityChecker(); 
if (sc.CheckSecurity(DirtyData)) 
    { 
    myCustomUserContext.Property1 = new GUID() 
    } 
return myCustomUserContext; 
} 


public class bool CheckSecurity(string DirtyData) 
{ 
//do string.split 
//maybe call a database, see if it's a token replay 
// return true if OK return false if not 
} 
} 

经修订的课题

一个静态方法

如果我创建的静态“实用程序”类是否会遇到并发问题(变量相互覆盖) e创建另一个对象的实例,然后调用方法--versus--直接简单地调用静态方法?

+0

我不确定你的意思是“我不确定变量将如何处理”。你能澄清吗? – Manfred 2010-08-06 02:32:42

+0

这里我使用“newstring”作为一个非常有限的局部变量。假设该方法非常强大,需要5秒才能完成。如果有另一个请求进入,而我的方法正在运行,会不会发生数据碰撞/覆盖?为了更进一步,我的方法可能会创建一些对象的新实例(非静态)并让它们执行某些操作。如果碰撞没有发生在我的方法中,它会发生在子对象中吗? – LamonteCristo 2010-08-06 02:40:51

+0

@ MakerOfThings7:我只是注意到你的评论在这里,只要newString和其他对象在静态方法中声明,你没事。举例来说,如果你不得不向其他班级发出这些对象,而且他们是在别处创建的,那肯定会有问题。 – umbyersw 2010-08-06 06:09:40

回答

1

。它有更多的事情要做,是不是比在问题中的代码可见的代码一些非常重要的点...

DoSomeThingToString方法是静态的,并且在该方法中声明的任何变量对于该线程的调用堆栈都是本地的。如果正在使用的变量在函数外部定义,那么您将在该内存上存在竞争条件。确保它看起来像这样,只使用局部变量:

public static string DoSomethingToString(string UntrustedString) 
{ 
    var newString = UntrustedString; 
    // operations on newString... 
    return newString; 
} 

AddNumber方法可能会遇到其他可能不明显的问题。如果这是真的你正在尝试做的,添加了许多,像这样做:

System.Threading.Interlocked.Increment(ref myInt); 

的Interlocked.Increment方法,保证了操作将在一个时钟周期内完成。

否则,在某些罕见情况下,使用lock关键字可能会非常棘手。这里有一些经验法则。始终锁定您创建并持有引用的对象,甚至更好,永不改变。这意味着:只读,并在创建类时分配内存地址。看起来像这样:

static int myInt=0; 
static readonly object aGoodLock = new object(); 
public static int MoreComplexIntStuff() 
{ 
    lock(aGoodLock) 
    { 
     // Do stuff with myInt... 
    } 
    return myInt; 
} 

此外,这不是整个故事。另一个问题是,无论何时访问变量myInt,即使它在这个类的另一部分中 - 或者如果它是公共的并在其他地方使用,则需要用一个锁包装它。不仅仅是任何锁,而是你使用的同一个锁,aGoodLock。

用这种方法帮助你的开发人员(也许是你自己的长期记忆)的最好方法是使变量和包装它的锁private,并使用属性公开myInt,你会小心使用get和set中的锁。

+0

很好的答案!你能告诉我新建一个对象并使用它的意义吗?该对象有什么特点?例如没有静态属性? – LamonteCristo 2010-08-06 13:26:25

+0

@ MakerOfThings7,如果你在静态方法中新建一个对象,它是你的,并且其他线程都不能使用它。如果该对象本身具有静态属性,那也可以。尽管没有关于手头问题的更多细节,但很难概括一个答案,因为有这么多“变数”。 :) – umbyersw 2010-08-06 17:26:06

2

调用你的静态方法的每个线程都有自己的调用堆栈。对DoSomethingToString()的每个调用都有自己的方法变量副本,完全独立于其他线程对该方法的任何其他调用(除非将变量声明为静态变量,即可能会混淆的变量 - 静态变量只有在程序中可以访问多个线程的一个实例)。

与往常一样,当多个线程访问共享资源时,您需要考虑并发性。当资源只存在于方法调用的上下文中时,并发性不是问题。

参见:https://stackoverflow.com/questions/511378/net-static-methods-and-its-effects-on-concurrencyt

+0

所以如果一个方法是静态的,那么这个方法中的变量是隐式静态的还是非静态的? – LamonteCristo 2010-08-06 02:45:12

+0

静态方法是一种可以在不实例化它所属的对象的情况下调用的方法。使一个静态方法不会使其变量变为静态的,您仍然需要在每个变量声明中明确使用static关键字来实现该变量。 – saille 2010-08-06 02:51:09

+0

@ MakerOfThings7:是的,在静态方法中声明的变量对于执行该代码的线程是本地的。这些变量的线程之间不会有共享内存,并且它们是线程安全的。 @saille:很好的回答,你的评论:静态关键字只能用于在VB.NET语言的方法中定义本地作用域的静态变量,如果这是你所指的。这种使用方式中没有很多好的例子,我会谨慎反对。这是我能找到的最好的例子:http://weblogs.asp.net/psteele/pages/7717.aspx – umbyersw 2010-08-06 05:53:38

1

我感觉你在考虑变量只能是实例或静态的,并且忘记局部变量与其中的任何一个不同。试想一下:

public class MyClass 
{ 
    public int InstanceInt; 
    public static int StaticInt; 
    public int InstanceMethod() 
    { 
     int i = new Random().Next(1, 50); 
     return i; 
    } 
    public static int StaticMethod() 
    { 
     int j = new Random().Next(1, 50); 
     return j; 
    } 
} 

这里InstanceInt是一个实例变量,并StaticInt一个静态变量。如果要由不同的线程访问它们,则这两个都需要锁定,但是,如果MyClass的实例由不同的线程访问,则InstanceInt只能由不同的线程访问。这可能发生在static MyClass AllThreadsSeeMe = new MyClass(),存储在一个静态集合中,明确地将它传递给另一个线程,等等,但否则不会。同时,在应用程序中运行的所有线程都可以自然访问该线程,即使您注意确保线程之间不共享MyClass的实例。

同时,ij对于它们的功能都是本地的。调用函数的每个线程将被赋予它们自己的副本ij,而不管有多少线程可以调用它们。因此它们本质上是线程安全的。只有当这些方法中的任何一个改变了一个静态变量或实例变量,或者读取了一个可变的静态或实例变量,这些变量可以被不同的方法改变,它们不是线程安全的(不可变的 - readonly - 变量也是线程安全的,没有办法另一个线程可以改变它们的值,因为没有线程可以改变它)。

+0

..在这种情况下,您使用的值类型很有趣。使用参考类型有什么不同? – LamonteCristo 2010-08-06 13:28:22

+0

引用类型有一个区别,即任何这些类型的变量(静态成员,实例成员和本地)都可以引用与另一个变量相同的对象。在这种情况下,我们认为从代码的一部分看线程安全的事情实际上可能不是这样,因为同一个对象被保存在一个变量中,该变量将它暴露给其他线程的交互。 它仍然认为本地变量本身总是线程安全的,但如果设置为成员(实例或静态)的值,它们可能不是。此外,分配本地 - >成员的操作。 – 2010-08-06 14:02:47

+0

尽管如此,与原始问题(处理字符串)特别相关的是,持有不可变对象的本地变量是线程安全的,因为没有其他线程可以更改它(使用字符串X,字符串本身在X处不能被改变,但是X所指的字符串可以)。不变性可以用于很多原因,并且帮助提供线程安全性就是其中之一。 – 2010-08-06 14:09:55

相关问题