views:

78

answers:

4

I have a static method like this

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

Since I know that multiple calls to:

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

will return an ever increasing number (that is shared among pages), I'm not sure how local the variables will be treated in DoSomethingToString();

I'd like to learn the conditions in which a static method can safely/unsafely be used in ASP.net just to put my multi-threaded brain to rest on this topic.

UPDATE:

Most of the discussion has been around value types. How do I know when it's safe to call methods (explicitly or implicitly) that change my reference types? Is it enough to looking at MSDN documentation and only use methods where it says "threadSafe"?

One example if what I call an implicit change is using String.Split() since it's part of the same class. I think there is a likelihood that some security characteristics are shared and there is less worry/diligence needed. (?)

What I'm calling an explicit change (for lack of a better word right now) is calling another method to do work... which can be static or an instance class. I think that more background/research work needs to be done to ensure that each object and method is ThreadSafe.

For the sake of discussion assume I have a method with this signature:

ValidateStringAndContext(string untrustedString, Object myCustomUserContext)

and it has a static method that references the following object

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
}
}

Revised Question

Would I run into concurrency issues (variables overwriting each other) if the static "utilities" class I create were to create an instance of another object and then call the method --versus-- simply calling a static method directly?

A: 

Check this site out to get a better understanding of Threading

Threading Explained

Alexander
+2  A: 

Each thread calling your static method has its own call stack. Every call to DoSomethingToString() has its own copy of the method's variables, completely independant of any other call to that method on another thread (unless you declare a variable as static, thats what you may be getting confused with - a static variable has only one instance that is accessible to multiple threads in your program).

As always, you need to consider concurrency when multiple threads are accessing a shared resource. When a resource only exists within the context of a method call, concurrency is a non-issue.

See also: http://stackoverflow.com/questions/511378/net-static-methods-and-its-effects-on-concurrencyt

saille
So if a method is static, the variables within that method are implicitly static or non-static?
MakerOfThings7
A static method is a method that can be called without instantiating the object it is a member of. Making a method static does not make its variables static, you still need to explicitly use the static keyword in each variable declaration to achieve that.
saille
@MakerOfThings7: Yes, variables that are declared within a static method are local to the thread executing that code. There will be no shared memory between threads possible for those variables and they are thread-safe.@saille: Great answer, re: your comment: The static keyword can only be used to define static variables of local scope within methods in the VB.NET language, if that is what you are referring to. There are not a lot of good examples out there of this usage, and I would caution against it. This is the best example I could find: http://weblogs.asp.net/psteele/pages/7717.aspx
umbyersw
@saille: re: your comment, if what you instead meant was to define a class-level static variable and then to access that static class-level variable within the static method... That would definitely be a problem... Unless you were managing access to that static variable using a lock around all usages. See my answer for an example.
umbyersw
+1  A: 

There are some very important points that have more to do with the code that is not visible than the code shown in the question...

The DoSomeThingToString method is static, and any variables declared within that method will be local to that thread's call stack. If the variables in use are defined outside the function, you will have race conditions on that memory. Be sure it looks like this, using only local variables:

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

The AddNumber method could be subject to other problems that might not be obvious. If this is really what you are trying to do, to add a number, do it like this:

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

The Interlocked.Increment method guarantees that the operation will be completed in one clock cycle.

Otherwise, the use of the lock keyword can be tricky in some rare situations. Here are some rules of thumb. Always lock on an object that you both create and hold the reference to, and even better, that you can never change. That means: readonly, and assigning the memory address upon creation of the class. That looks like this:

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

Also, this isn't the whole story. Another gotcha is that anytime the variable myInt is accessed, even if it's in another part of this class - or if it's public and used somewhere else, you need to wrap it with a lock. And not just any lock, but the same one that you're using, aGoodLock.

The best way to help your fellow developers (and perhaps your own long-term memory) with this is to make the variable and the lock that wraps it private, and to expose myInt using a Property where you would be careful to use the lock in the get and set.

umbyersw
@umbyersw Great answer! Can you tell me the implications of new'ing up a object and working with it? What are the characteristics of that object? e.g. no static properties?
MakerOfThings7
@MakerOfThings7, If you new up an object in a static method, it's yours and no other thread can use it. If that object itself has static properties, that's fine too. It's hard to generalize an answer though without more specifics on the problem at hand, because there are so many "variables". :)
umbyersw
+1  A: 

I get the feeling that you are thinking that variables can be only instance or static, and forgetting that local variables are different to either. Consider:

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;
    }
}

Here InstanceInt is an instance variable, and StaticInt a static variable. Both of these require locking if they are going to be accessed by different threads, however, InstanceInt is only going to be accessed by different threads if an instance of MyClass is accessed by different threads. This could happen with static MyClass AllThreadsSeeMe = new MyClass(), storage in a static collection, explicitly passing it to another thread, or so on, but otherwise will not. StaticInt meanwhile is inherently accessible to all threads running in the application, even if you take care to make sure that no instance of MyClass is shared between threads.

Meanwhile, i and j are both local to their functions. Each thread calling the function will be given their own copy of i or j, irregardless to how many threads could call them. Hence they are inherently thread-safe. It is only if either of these methods alter a static or instance variable, or read a mutable static or instance variable that could be altered by a different method, that they are not thread-safe (immutable - readonly - variables are also threadsafe because there's no way another thread can change their value, given that no thread at all can change it).

Jon Hanna
@Jon Hanna... It's interesting you're using a value type in this case. What is different when using a reference-type?
MakerOfThings7
There is one difference with a reference type, which is that any of these types of variables (static members, instance members and local) can refer to the same object as another variable. In this case something that we would believe thread-safe from looking at one part of the code, may in fact not be, because the same object is held in a variable that exposes it to interactions from other threads.It still holds that local variables are in themselves always thread safe, but if set to the value of a member (instance or static) they may not be. Also, the operation of assigning local -> member.
Jon Hanna
One further thing though, that is particularly relevant to your original question (that deals with a string), is that a local variable holding an immutable object is thread-safe, as no other thread can change it (with string X, the string itself at X can't be changed, but which string X refers to can). Immutability can be useful for many reasons, and helping provide thread-safety is one of them.
Jon Hanna
@Jon: Great answer, I like that you are highlighting the differences between instance, static, and stack variables. Also, value types vs. reference types. IMHO, .NET does not provide enough information to programmers that these "different things should look different".
umbyersw
Thank you. I agree that it is under-explored. All the more so the advantages of immutability, which seems only to be mentioned in terms of how StringBuilder and UriBuilder let us get around that, and ignoring that string and Uri are immutable for a reason! One of those reasons is the effect upon thread safety. The language itself is great here in having readonly rather than the way C++ uses const in different ways in different contexts, but the documentation isn't clear (I learnt about immutability from writers on C++, not on C#).
Jon Hanna