Должен ли я использовать блокировку в следующем сценарии - PullRequest
3 голосов
/ 15 мая 2011

Я разработал класс обёртки стека.Моя путаница заключается в том, должен ли я использовать lock во время выталкивания или помещения объектов в переменную стека "ParameterStack".Пожалуйста, дайте мне знать, является ли этот класс потокобезопасным или нет.

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 для учебных целей.

Ответы [ 5 ]

7 голосов
/ 15 мая 2011

выглядит нормально. Существует (довольно теоретический) аргумент, что блокировка на 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 голос
/ 15 мая 2011

Да, вы должны.Стек не синхронизируется по умолчанию в C #.

1 голос
/ 15 мая 2011

Да, это потокобезопасно.Пока любое использование внутреннего стека находится в пределах блокировки, его можно будет безопасно использовать с несколькими потоками.

Вы можете использовать Stack<T>, чтобы избежать всех приведений.Или, как говорит Oxilumin, используйте ConcurrentStack, если вы не просто пытаетесь научиться делать что-то поточно-безопасное.

1 голос
/ 15 мая 2011

Вы должны использовать 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 type для RawObject, если хотите проверить тип. В вашем коде вы получите исключение, если попытаетесь Pop объект другого типа.

0 голосов
/ 12 августа 2011

Знаете ли вы о классе ConcurrentStack? это эффективная многопоточная реализация, использующая free-free

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...