Существуют ли общие правила / рекомендации для того, что делает метод потокобезопасным? Я понимаю, что, возможно, существует миллион разовых ситуаций, но что в целом? Это так просто?
- Если метод обращается только к локальным переменным, это потокобезопасно.
Это оно? Это относится и к статическим методам?
Один ответ, предоставленный @Cybis, был:
Локальные переменные не могут быть разделены между потоками, потому что каждый поток получает свой собственный стек.
Это относится и к статическим методам?
Если методу передается ссылочный объект, нарушает ли это безопасность потока? Я провел некоторые исследования, и есть много примеров определенных случаев, но я надеялся, что смогу определить, используя всего несколько правил, рекомендации, которым нужно следовать, чтобы убедиться, что метод является потокобезопасным.
Итак, я предполагаю, что мой главный вопрос: «Есть ли короткий список правил, которые определяют потокобезопасный метод? Если да, то каковы они?»
РЕДАКТИРОВАТЬ
Много хороших моментов было сделано здесь. Я думаю, что реальный ответ на этот вопрос: «Нет простых правил для обеспечения безопасности потоков». Прохладно. Хорошо. Но в целом я думаю, что принятый ответ дает хорошее, краткое резюме. Всегда есть исключения. Пусть будет так. Я могу жить с этим.
источник
Ответы:
Если метод (экземпляр или статический) ссылается только на переменные, ограниченные областью действия этого метода, он является поточно-ориентированным, поскольку каждый поток имеет свой собственный стек:
В этом случае несколько потоков могут вызывать
ThreadSafeMethod
одновременно без проблем.Это также верно, если метод вызывает другой метод класса, который ссылается только на переменные локальной области видимости:
Если метод получает доступ к каким-либо (объектным) свойствам или полям (экземпляру или статическому), вам необходимо использовать блокировки, чтобы гарантировать, что значения не будут изменены другим потоком.
Вы должны знать, что любые параметры, передаваемые методу, которые не являются ни структурными, ни неизменяемыми, могут быть изменены другим потоком вне области метода.
Для обеспечения правильного параллелизма вам нужно использовать блокировку.
Для получения дополнительной информации см. ссылку на оператор блокировки C # и ReadWriterLockSlim .
Блокировка в основном полезна для предоставления по одному функциональности за раз,
ReadWriterLockSlim
полезна, если вам нужно несколько читателей и один писатель.источник
private string someValue;
это неstatic
так, каждый экземпляр получит отдельную копию этой переменной. Так что вы можете объяснить, как это не потокобезопасно?Thing
класса, доступ к которому осуществляется несколькими потокамиАбсолютно нет. Вы можете написать программу, имеющую доступ только к одной локальной переменной из одного потока, который, тем не менее, не является потокобезопасным:
https://stackoverflow.com/a/8883117/88656
Точно нет.
Точно нет. Отличительной характеристикой локальной переменной является то, что она видна только внутри локальной области , а не то, что она размещена во временном пуле . Это совершенно законно и возможно получить доступ к одной и той же локальной переменной из двух разных потоков. Вы можете сделать это, используя анонимные методы, лямбда-выражения, блоки итераторов или асинхронные методы.
Точно нет.
Может быть.
Вам придется научиться жить с разочарованием. Это очень сложный предмет.
Нет. Как вы видели из моего примера ранее , пустой метод может быть не поточно-ориентированным . Вы также можете спросить: «Есть ли короткий список правил, обеспечивающих корректность метода ». Нет, нет Безопасность потоков - не что иное, как чрезвычайно сложный вид правильности.
Более того, тот факт, что вы задаете вопрос, указывает на ваше фундаментальное недопонимание в отношении безопасности потоков. Безопасность потоков - это глобальное , а не локальное свойство программы. Причина, по которой так трудно получить права, состоит в том, что вы должны полностью знать поведение потоков всей программы , чтобы обеспечить ее безопасность.
Опять же, посмотрите на мой пример: каждый метод тривиален . Именно способ, которым методы взаимодействуют друг с другом на «глобальном» уровне, делает программу тупиковой. Вы не можете смотреть на каждый метод и отмечать его как «безопасный», а затем ожидать, что вся программа безопасна, больше, чем вы можете сделать вывод, что, поскольку ваш дом сделан из 100% -го пустотелого кирпича, этот дом также не полый. Пустота дома - это глобальная собственность всего этого, а не совокупность свойств его частей.
источник
class C { public static Func<int> getter; public static Action<int> setter; public static void M() { int x = 0; getter = ()=>x; setter = y=>{x=y;};} }
M (), затем вызовите C.getter и C.setter в двух разных потоках. Теперь локальная переменная может записываться и считываться в двух разных потоках, даже если она локальная. Опять же: определяющей характеристикой локальной переменной является то, что она локальная , а не то, что она находится в стеке потока .Там нет жесткого и быстрого правила.
Вот некоторые правила, чтобы сделать потокобезопасным код в .NET, и почему это не очень хорошие правила:
lock
иметь общую вещь. Все замки должны быть выполнены в одинаковом порядке. Это сделает поток кода безопасным, но это будет невероятно медленно, и вы можете также не использовать несколько потоков.Не существует правила, обеспечивающего безопасность потока кода, единственное, что вы можете сделать, это убедиться, что ваш код будет работать независимо от того, сколько раз он активно выполняется, каждый поток может быть прерван в любой момент, причем каждый поток находится в свое собственное состояние / местоположение, и это для каждой функции (статической или другой), которая обращается к общим объектам.
источник
Он должен быть синхронизирован с использованием блокировки объекта, без сохранения состояния или неизменяемым.
ссылка: http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html
источник