Вопрос безопасности темы C # - PullRequest
0 голосов
/ 29 сентября 2010

Как мне сделать код, подобный этому потокобезопасному?

public static class Converter
{
    public static string ConvertNameToNickname(string name)
    {
        if (name.Equals("John"))
        {
            return "Johnathon";
        }

        return name;
    }
}

Или это уже потокобезопасно, поскольку "имя" является локальной переменной?Я просто хочу убедиться, что ConvertNameToNickname был вызван двумя разными потоками, на имя которого оно вычислялось, не переходили ли другие потоки.из этих ответов были довольно полезны, но я все еще не нашел ответ, который искал, поэтому позвольте мне немного изменить его и задать тот же вопрос.Как бы я сделал этот поток кода безопасным, учитывая параметр изменяемого типа?Или это вообще возможно?Если я добавлю блокировку {} вокруг всего тела метода (показанного в примере 2), все равно возможно ли изменить переменную экземпляра "name", прежде чем мы войдем в блок оператора блокировки?Пример 2:

private static readonly object _lockObject = new object();

public static class Converter
{
    public static string ConvertNameToNickname(StringBuilder name)
    {
        lock(_lockObject)
        {
            if (name.ToString().Equals("John"))
            {
                return "Johnathon";
            }

            return name;
        }
    }
}

Ответы [ 2 ]

7 голосов
/ 29 сентября 2010

Или это уже потокобезопасно, поскольку "имя" является локальной переменной?

Закрыть.Это потокобезопасно, но не из-за локальных переменных.Однако, поскольку string в .NET является неизменным, это потокобезопасно.Ключ к поточной безопасности без синхронизации всегда работает с неизменяемыми типами.С изменяемыми типами даже такие методы, как .Equals, могут не быть потокобезопасными.

Если бы строка была изменяемым классом, это не обязательно было бы потокобезопасным.


Редактировать:

Хорошо, некоторые из этих ответов были довольно полезными, но я все еще не нашел ответ, который искал, поэтому позвольте мне немного изменить его и задать тот же вопрос.Как бы я сделал этот поток кода безопасным, учитывая параметр изменяемого типа?Или это вообще возможно?

Да, это потенциально возможно.Тем не менее, это требует синхронизации некоторой формы, чтобы быть правильной.Использование блокировки - один из вариантов.

Если я добавлю блокировку {} вокруг всего тела метода (показано в примере 2), все еще возможно изменение переменной «name» перед изменениеммы вводим блок оператора блокировки?

К сожалению, это так.Блокировка предотвращает одновременный вызов этого кода из двух разных потоков.По сути, вы делаете это конкретное использование потока «name» безопасным.Однако, если «name» используется в другом месте вашей программы, все еще возможно, что оно может быть изменено какой-либо другой функцией при использовании в вашей блокировке.Это может привести к тонкому состоянию гонки.

Безопасность нитей сложно понять правильно.Наилучшим вариантом для поточно-безопасного использования изменяемых типов обычно является предоставление собственных, поточно-безопасных типов, где сам тип обрабатывает всю необходимую ему внутреннюю синхронизацию, а общедоступный API полностью поточно-ориентирован.Это единственный способ гарантировать, что никто не будет «связываться» с вашими данными, даже если вы ограничиваете использование.

Именно здесь вступают в игру неизменяемые типы - они устраняют все эти проблемы,так как их состояние не может быть изменено после создания.Любой может использовать их и создавать больше, не рискуя при этом для самого типа.

2 голосов
/ 29 сентября 2010

Да, это уже потокобезопасно, поскольку «имя» - это локальная переменная, назначенная неизменяемому объекту.

Локальные параметры передаются по значению, поэтому всегда создается копия значения / ссылки, в отличие от параметра ref , в этом случае могут возникнуть проблемы с параллелизмом, если это ссылкав поле.

...