2011-05-15 40 views
3

我设计了一个Stack包装类。我的困惑是,如果我在弹出或推送对象到堆栈变量“ParameterStack”时使用lock。请让我知道,这个类是否是线程安全的。我应该在下面的场景中使用锁定

public static class StackManager 
{ 
    private static Stack ParameterStack = new Stack(); 

    public static T Pop<T>() 
    { 
     T RawObject; 
     T Result = default(T); 

     lock (ParameterStack) 
     { 
      RawObject = (T)ParameterStack.Pop(); 
     } 

     if (RawObject != null && RawObject is T) 
      Result = (T)RawObject; 

     return (T)Result; 
    } 

    public static void Push<T>(T Data) 
    { 
     lock (ParameterStack) 
     { 
      ParameterStack.Push(Data); 
     } 
    } 
} 

我已经创建了这个StackManager类用于学习目的。

回答

7

看起来没问题。有一个(相当理论上的)论点,锁定在ParameterStack本身并不完全安全,因为你不拥有代码。假设堆栈内某个地方有一个lock(this),你可能会陷入僵局。

public static class StackManager 
{ 
    private static Stack parameterStack = new Stack(); 
    private static object stackLock = new object(); 

    // now use lock(stackLock) instead of lock(ParameterStack) 

} 
1

你应该使用ConcurrentStack你的情况。 如果你不能够使用ConcurrentStack - 您可以使用Stack.Synchronized()方法:

Stack mySynchronizedStack = Stack.Synchronized(myStack); 

但是,即使你使用Synchronized()方法枚举仍然不是线程安全的,你应该使用锁来枚举你的筹码。

Stack myStack = new Stack(); 
lock (myStack.SyncRoot) 
{ 
    foreach (var element in myStack) 
    { 
    } 
} 

不幸的是,但Stack通用版本没有Synchonization()方法。 所以,你的代码应该是:

public static class StackManager 
{ 
    private static Stack ParameterStack; 

    static StackManager() 
    { 
     ParameterStack = Stack.Synchronized(new Stack()); 
    } 

    public static T Pop<T>() 
    { 
     object RawObject = ParameterStack.Pop(); 

     return RawObject is T ? (T)RawObject : default(T); 
    } 

    public static void Push<T>(T Data) 
    { 
     ParameterStack.Push(Data); 
    } 
} 

,如果你想查询的类型也应该使用object类型RawObject。在你的代码中,如果你尝试Pop不同类型的对象,你会得到一个异常。

+0

是的,但这需要Fx4,并不会履行'学习的目的' – 2011-05-15 07:22:24

+0

感谢您更新的代码片段,如上所述,我将肯定会转移到ConcurrentStack .NET Framework 4. – AbrahamJP 2011-05-15 07:55:59

1

是的,你应该。在C#中,默认情况下堆栈不同步。

1

是的,它是线程安全的。只要内部堆栈的任何使用位于一个锁内,它就可以安全地用于多个线程。

你可以使用Stack<T>来避免所有的转换。或者如oxilumin所说的,如果你不只是试图学习如何制作线程安全的东西,那就使用ConcurrentStack。

+0

“您可以使用堆栈” - 我认为这个堆栈用于存放多种类型。看看这个名字。 – 2011-05-15 07:37:05

+0

好点。我可能不应该在我的早晨咖啡前回答问题;) – 2011-05-15 07:38:10

0

您是否知道ConcurrentStack类?这是一个高效的线程安全实现使用无锁

相关问题