2010-08-06 41 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

相關問題