Thread safe что это
Прелесть open-source кода в его открытости :)) Т.е. при наличии ума/времени/желания можно разобраться, как именно работает программа. Обратная сторона такого кода — сложность в получении нужных скомпилированных пакетов. Например, PHP можно скачать в виде исходников для Nix-систем с последующей компиляцией/сборкой. Для Windows все уже собрано, но готовых бинарных пакетов много! Варианты с «thread safe/non thread safe«, VC6/VC9 и разные версии самого PHP. Статья создана для прояснения ситуации. В основе — разные источники, частично — перевод с английского. Все для того, чтоб в следующий раз мне опять не разбираться — «че к чему!?».
Нужная версия PHP зависит от версии веб-сервера, на котором он будет использоваться. Например, Apache 1.3.x работает с РНР версии 3.0.х, Apache 2.х работает с РНР версии 4.0 и выше. Но это не такая уж проблема, ориентируйтесь на более новые стабильные релизы и то, что стоит у хостера.
Что за приписки VC6, VC9, VC11? Исходники PHP под Windows компилируются в Visual Studio. VC9 получается при компиляции в VS 2008, VC11 — Visual Studio 2012. Соответственно, чтобы все это дело у вас работало, на компе должны быть установлены библиотеки Visual C++ Redistributable for Visual Studio соответствующего года. Некоторые разъяснения по этому поводу здесь.
Кроме того, если web-сервером у вас будет старенький Apache с сайта apache.org, то нужно качать VC6 версии PHP, для компиляции которых использовался Visual Studio 6. Если же PHP будет работать для IIS или в связке с более новым Apache, то можно собрать что-нибудь посовременнее 😉
Для меня главным ступором в выборе служит хостер. Сейчас есть стабильная версия PHP 5.5.4, а у него до сих пор 5.2.17!
Теперь самая интересная часть: «thread safe or non thread safe?»
Вольный перевод статьи Difference between PHP thread safe and non thread safe binaries (Dominic Ryan, 27.09.2007)
Я настолько ломанного английского еще не видел :(( Хотел по-быстрому перевести статью, но с трудом понимаю, что автор понаписал. Постоянные переходы между «what-is-that» и сложно-составные предложения вообще выносят мОСк. Перевод на русский так же осложняется тем, что у меня не хватает знаний и фантазии как правильно по-русски должно называться то, что обычно пишется только на английском %) Например техническое понятие «multi proccess architecture» я ни разу не видел на русском, а мой перл «потоко-небезопасные» вообще под вопросом здравого смысла. Вообщем, что получилось, то привожу.
Разница между thread safe и non thread safe бинарными пакетами PHP
С тех пор, когда PHP впервые появился под Windows 20 октября 2000 года в версии PHP 3.0.17, его бинарные пакеты всегда были собраны как потоко-безопасные (thread safe, TS). Основание следующее: Windows использует мульти-поточную архитектуру работы, а Nix-системы поддерживают мульти-процессовую архитектуру. Если PHP был скомпилирован как мульти-процессовое CGI-приложение вместо мульти-поточного, то его использование в качестве CGI-модуля под Windows на сервере IIS приводит к сильным тормозам и загрузке процессора. С другой стороны, можно подключить PHP на IIS, как ISAPI-модуль (требуется мульти-поточная сборка — прим. переводчика). Тогда возникает другая проблема: некоторые популярные расширения PHP разработаны с ориентиром на Unix/Linux, т.е. с мульти-процессовой архитектурой, что приводит к краху PHP, подключенному на IIS в качестве ISAPI-модуля. Т.о. создание CGI — наиболее стабильная среда для PHP на IIS с основным недостатком, что это ужасно медленно. Приходится загружать и выгружать всю среду PHP из памяти каждый раз, когда есть запрос.
В то время было несколько вариантов для увеличения производительности PHP на IIS. Первый — использовать кеширование опкода программами типа eAccelerator, которые сохраняют PHP-скрипты в частично скомпилированном состоянии на диске и/или в памяти. Такой подход значительно сокращает время выполнения скрипта. Другой вариант заключался в настройке IIS на использование PHP в режиме FastCGI. При этом PHP-процесс после отработки не закрывался, а получал новое задание с очередным php-запросом. К тому же можно было запустить несколько PHP-процессов одновременно, ощутимо ускоряя обработку запросов, что являлось бонусом CGI-режима PHP. При этом могли быть незначительные проблемы с совместимостью PHP-расширений. Это по-прежнему самый быстрый способ использования PHP, и именно на задание такой конфигурации IIS настроен установщик «IIS Aid PHP Installer».
Бинарники, собранные в потоко-небезопасном режиме (non thread safe, NTS), позволяют сконфигурировать IIS (и другие веб-сервера под Windows) на использование PHP, как стандартный CGI-интерфейс с сильным приростом производительности, т.к. в этом случае (в такой сборке) PHP-процессу не нужно дожидаться синхронизации нитей. При сравнении работы «thread safe» и «non thread safe» бинарных пакетов PHP на IIS в качестве стандартного CGI-интерфейса прирост быстродействия составляет до 40%, но это все равно не так шустро как использование опкода в FastCGI методе. А самый большой косяк в том, что нельзя стабильно использовать потоко-небезопасные бинарники вместе с потоко-безопасными. Это значит, что вы не можете использовать системы кеширования опкода типа eAccelerator в среде PHP, созданной потоко-небезопасными бинарными пакетами (утверждение, верное на момент написания статьи).
Если потоко-небезопасный PHP нельзя сконфигурировать до такой же скорости, что и потоко-безопасную среду, то зачем он нужен в такой сборке? Возвращаемся к FastCGI и разработкам Microsoft в этой области за последние несколько лет. Кодеры мелкомягких создали свой вариант FastCGI, который позволяет конфигурировать потоко-небезопасные бинарники PHP в режиме FastCGI, что доводит производительность до скорости света 🙂
Из статьи я сделал вывод, что тормоза наблюдаются только при использовании с веб-сервером IIS. В любом случае, тупняков под Windows+Apache я не видел. В ней же сказано, что можно разогнать NTS-сборку на любом веб-сервере, но я не представляю себе такой конфиг Apache.
Concurrent Programming Fundamentals— Thread Safety

thread-safety or thread-safe code in Java refers to code that can safely be utilized or shared in concurrent or multi-threading environment and they will behave as expected.
Thread-safety is one of the risks introduced by using threads in Java and I have seen java programmers and developers struggling to write thread-safe code or just understanding what is thread-safe code and what is not?
How to make Thread-Safe Code in Java
Before you learn how to write a thread-safe code you need to understand what is thread-safety and there is no better way to that than looking at a non-thread-safe code. So, let’s see an example of the potential, not thread-safe code, and learn how to fix that.
Example of Non-Thread-Safe Code in Java
Here is an example of a non-thread-safe code, look at the code, and find out why this code is not thread-safe?
Example 1
The above example is not thread-safe because ++ (the increment operator) is not an atomic operation and can be broken down into reading, update, and write operations.
If multiple thread call getCount() approximately same time each of these three operations may coincide or overlap with each other for example while thread 1 is updating value, thread 2 reads and still gets old value, which eventually let thread 2 override thread 1 increment and one count is lost because multiple threads called it concurrently.
Example 2
What can happen if we use non thread-safe implementation in multi-threaded environment:
In the most general case of multi-threaded environment we shall assume that all methods will be called on random threads at random times. The implementation we used for a single-threaded environment is not safe anymore. It is not hard to imagine a flow when two distinct threads attempt to register new Observers at the same time, and end up leaving our system screwed up. One such flow could be (there are many other flows which could break non-thread-safe implementation):
- Thread A invokes registerObserver(Observer)
- Thread A executes mObservers == null check and proceeds to instantiation of a new set
- before Thread A got a chance to create a new set, OS suspended it and resumed execution of Thread B
- Thread B executes steps 1 and 2 above
- since Thread A hasn’t instantiated the set yet, Thread B instantiates a new set and stores a reference to it in mObservers
- Thread B adds an observer to the newly created set
- at some point OS resumes execution of Thread A (which was suspended right before instantiation of a new set)
- Thread A instantiates a new set and overrides the reference in mObservers
- Thread A adds an observer to the newly created set
Despite the fact that both calls to registerObserver(Observer) completed successfully, the end result is that only one observer will be notified when notifyObservers() called. It is important to understand that any of the observers could end up being “ignored”, or both observers could be registered successfully – the outcome depends on the scheduling of threads by OS which we can’t control. This non-determinism is what makes multi-threading bugs very hard to track and resolve.
How to make Thread-Safe code in Java
There are multiple ways to make this code thread-safe in Java:
1) Use the synchronized keyword in Java and lock the getCount() method so that only one thread can execute it at a time which removes the possibility of coinciding or interleaving.
2) use Atomic Integer, which makes this ++ operation atomic and since atomic operations are thread-safe and saves the cost of external synchronization.
Here is a thread-safe version of NumberCounter class in Java:
Important points about Thread-Safety in Java
Here are some points worth remembering to write thread-safe code in Java, this knowledge also helps you to avoid some serious concurrency issues in Java-like race condition or deadlock in Java:
1) Immutable objects are by default thread-safe because their state can not be modified once created. Since String is immutable in Java, it’s inherently thread-safe.
2) Read-only or final variables in Java are also thread-safe in Java.
3) Locking is one way of achieving thread-safety in Java.
4) Static variables if not synchronized properly become a major cause of thread-safety issues.
5) Example of thread-safe class in Java: Vector, Hashtable, ConcurrentHashMap, String, etc.
6) Atomic operations in Java are thread-safe like reading a 32-bit int from memory because it’s an atomic operation it can’t interleave with other threads.
7) local variables are also thread-safe because each thread has there own copy and using local variables is a good way to write thread-safe code in Java.
8) In order to avoid thread-safety issues minimize the sharing of objects between multiple threads.
9) Volatile keyword in Java can also be used to instruct thread not to cache variables and read from main memory and can also instruct JVM not to reorder or optimize code from threading perspective.
Что означает threadsafe?
недавно я попытался получить доступ к текстовому поле из потока (кроме потока пользовательского интерфейса), и было создано исключение. Он сказал что-то о «коде, не являющемся потокобезопасным», и поэтому я закончил тем, что написал делегат (образец из MSDN помог) и вызвал его вместо этого.
но даже при этом я не совсем понимал, зачем нужен весь дополнительный код.
обновление: Столкнусь ли я с серьезными проблемами, если проверю
11 ответов
Эрик Липперт есть хороший пост в блоге под названием что это за вещь, которую вы называете «потокобезопасной»? об определении безопасности потоков, как найдено в Википедии.
3 важные вещи, извлеченные из ссылки :
«код является потокобезопасным, если он работает правильно во время одновременное выполнение несколькими потоками.»
» в частности, он должен удовлетворять потребность в нескольких потоках для доступ к тому же общие данные, . «
» . и необходимость доступа только к одному общему фрагменту данных потока в любой момент времени.»
определенно стоит читать!
в простейшем из терминов threadsafe означает, что безопасно получать доступ из нескольких потоков. Когда вы используете несколько потоков в программе и каждый из них пытается получить доступ к общей структуре данных или расположение в памяти нескольких плохих вещей может случиться. Итак, вы добавляете дополнительный код, чтобы предотвратить эти плохие вещи. Например, если два человека писали один и тот же документ одновременно, второй человек, которого нужно сохранить, перезапишет работу первого человека. Чтобы сделать его потокобезопасным затем вы должны заставить человека 2 ждать, пока человек 1 выполнит свою задачу, прежде чем разрешить человеку 2 редактировать документ.
Википедия имеет статью о безопасности резьбы.
этой определений страницы (вы должны пропустить объявление — извините) определяет его так:
в компьютерном программировании thread-safe описывает часть программы или процедуру, которая может быть вызвана из нескольких потоков программирования без нежелательного взаимодействия между потоками.
поток-это путь выполнения программы. Однопоточная программа будет иметь только одну нить и поэтому эта проблема не возникает. Практически все программы GUI имеют несколько путей выполнения и, следовательно, потоков-один для обработки отображения GUI и передачи пользовательского ввода, другие для фактического выполнения операций программы. Это так, что пользовательский интерфейс по-прежнему реагирует во время работы программы.
модуль потокобезопасен, если он гарантирует, что он может поддерживать свои инварианты перед многопоточным и параллельным использованием.
здесь модуль может быть структурой данных, классом, объектом, методом / процедурой или функцией. В основном это фрагмент кода и связанные с ним данные.
гарантия потенциально может быть ограничена определенными средами, такими как определенная архитектура ЦП, но должна выполняться для этих сред. Если нет явного разграничения сред, затем обычно подразумевается, что для всех сред код может быть скомпилирован и выполнен.
Thread-небезопасные модули мая функция правильно под mutli-threaded и параллельным использованием, но это часто больше до удачи и совпадения, чем тщательный дизайн. Даже если какой-то модуль не сломается для вас, он может сломаться при перемещении в другие среды.
многопоточные ошибки часто трудно отлаживать. Некоторые из них только случаются иногда, в то время как другие проявляют агрессивность — это тоже может быть специфичной средой. Они могут проявляться как неуловимо неправильные результаты или тупики. Они могут испортить структуру данных непредсказуемым образом и вызвать появление других, казалось бы, невозможных ошибок в других удаленных частях кода. Это может быть очень специфичным для приложения, поэтому трудно дать общее описание.
просто thread safe означает, что метод или экземпляр класса могут использоваться несколькими потоками одновременно без каких-либо проблем.
рассмотрим следующий способ:
теперь поток A и поток B оба хотели бы выполнить AddOne (). но сначала запускается A и считывает значение myInt (0) в tmp. Теперь по какой-то причине планировщик решает остановить поток A и отложить выполнение потока B. поток B теперь также считывает значение myInt (все еще 0) в переменной tmp. Поток B завершает весь метод, поэтому в конце myInt = 1. И 1 возвращается. Теперь снова очередь нити А. Нить а продолжается. И добавляет 1 в tmp (tmp был 0 для потока A). А затем сохраняет это значение в myInt. myInt снова 1.
таким образом, в этом случае метод AddOne вызывался два раза, но поскольку метод не был реализован в потокобезопасном способе, значение myInt не 2, как ожидалось, а 1, потому что второй поток читал переменную myInt прежде чем первый поток закончил его обновление.
создание потокобезопасных методов очень сложно в нетривиальных случаях. И существует довольно много техник. В Java вы можете пометить метод как synchronized, это означает, что только один поток может выполнять этот метод в данный момент времени. Остальные нити стоят в очереди. Это делает метод потокобезопасным, но если в методе много работы, то это тратит много места. Другой метод —‘отметить только небольшую часть метод как synchronized’ путем создания замка или семафора и блокировки этой небольшой части (обычно называемой критическим разделом). Есть даже некоторые методы, которые реализованы как потокобезопасные без блокировки, что означает, что они построены таким образом, что несколько потоков могут проходить через них одновременно без каких-либо проблем, это может быть случай, когда метод выполняет только один атомарный вызов. Атомарные вызовы-это вызовы, которые не могут быть прерваны и могут выполняться только одним потоком в время.
вы можете получить больше объяснений из книги «параллелизм Java на практике»:
класс является потокобезопасным, если он ведет себя правильно при доступе из нескольких потоков, независимо от планирования или чередования выполнения этих потоков средой выполнения и без дополнительной синхронизации или другой координации со стороны вызывающего кода.
потокобезопасность: потокобезопасная программа защищает данные от ошибок согласованности памяти. В сильно многопоточной программе потокобезопасная программа не вызывает побочных эффектов с несколькими операциями чтения/записи из нескольких потоков на одних и тех же объектах. Различные потоки могут совместно использовать и изменять данные объекта без ошибок согласованности.
вы можете достичь безопасности потоков с помощью расширенного API параллелизма. Эта документация страница обеспечивает хорошие программируя конструкции для того чтобы достигнуть безопасности потока.
Объекты Блокировки поддержка блокировки идиомы, которые упрощают многие параллельные приложения.
исполнители определите API высокого уровня для запуска и управления потоками. Реализации исполнителя, предоставляемые java.утиль.concurrent обеспечивает управление пулом потоков, подходящее для крупномасштабного приложения.
Параллельные Коллекции упрощения управления большими коллекциями данных и может значительно уменьшить потребность в синхронизации.
Атомные Переменные есть функции, которые минимизируют синхронизацию и помогают избежать ошибок согласованности памяти.
ThreadLocalRandom (в JDK 7) обеспечивает эффективную генерацию псевдослучайных чисел из различные потоки.
смотрите java.утиль.параллельный и java.утиль.параллельный.атомный пакеты тоже для других конструкций программирования.
в реальном мире примером для непрофессионала является
предположим, у вас есть банковский счет в интернете и мобильном банке, и ваш счет имеет только 10$. Вы выполнили перевод баланса на другой счет с помощью мобильного банкинга и в то же время вы делали покупки в интернете с помощью того же банковского счета. Если этот BankAccount не «потокобезопасен», то банк разрешит вам выполнить две транзакции одинаково, и тогда банк обанкротится.
ThreadSafe означает, что состояние объекта не меняется, если одновременно несколько потоков пытаются получить доступ к объекту.
вы явно работаете в среде WinForms. Элементы управления WinForms демонстрируют сродство потоков, что означает, что поток, в котором они создаются, является единственным потоком, который можно использовать для доступа к ним и их обновления. Вот почему вы найдете примеры на MSDN и в других местах, демонстрирующие, как Маршалл вызова обратно в основной поток.
обычная практика WinForms должна иметь один поток, который посвящен всей вашей работе пользовательского интерфейса.
Я нахожу понятие http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 быть тем, что я обычно считаю небезопасным потоком, когда метод имеет и полагается на побочный эффект, такой как глобальная переменная.
например, я видел код, который отформатировал числа с плавающей запятой в строку, если два из них выполняются в разных потоках, глобальное значение decimalSeparator может быть навсегда изменено на ‘.’
чтобы понять безопасность потоков, прочитайте ниже разделы:
4.3.1. Пример: Отслежыватель Корабля Используя Делегирование
в качестве более существенного примера делегирования давайте построим версию трекера транспортного средства, которая делегирует потокобезопасный класс. Мы храним местоположения на карте, поэтому мы начинаем с потокобезопасной реализации Карты, ConcurrentHashMap . Мы также храним местоположение, используя неизменяемый класс Point вместо MutablePoint , как показано в листинге 4.6.
в листинге 4.6. Неизменяемый класс точек, используемый DelegatingVehicleTracker.
Point является потокобезопасным, потому что она неизменна. Неизменяемые значения можно свободно публиковать и публиковать, поэтому нам больше не нужно копировать местоположения при их возврате.
DelegatingVehicleTracker в листинге 4.7 не используется явная синхронизация; весь доступ к состоянию управляется ConcurrentHashMap и все ключи и Значения карты неизменяемы.
листинг 4.7. Делегирование безопасности потоков ConcurrentHashMap.
>
если бы мы использовали оригинальные MutablePoint класс вместо точки, мы будем нарушать инкапсуляцию, позволяя getLocations опубликовать ссылку на изменяемое состояние, которое не является потокобезопасным. Обратите внимание, что мы немного изменили поведение класса Vehicle tracker; в то время как версия монитора вернула снимок из местоположений делегирующая версия возвращает немодифицируемое, но» живое » представление местоположений транспортного средства. Это означает, что если поток A вызывает getLocations и поток B позже изменяет местоположение некоторых точек, эти изменения отражаются на карте, возвращенной потоку A.
4.3.2. Независимые Переменные Состояния
мы также можем делегировать безопасность потоков более чем одной базовой переменной состояния, если эти базовые переменные состояния являются независимыми, что означает, что сложный класс не накладывает никаких инвариантов с участием нескольких переменных состояния.
VisualComponent в листинге 4.9 представлен графический компонент, позволяющий клиентам регистрировать прослушиватели для событий мыши и нажатия клавиш. Он поддерживает список зарегистрированных прослушивателей каждого типа, чтобы при возникновении события можно было вызвать соответствующие прослушиватели. Но нет никакой связи между набором слушателей мыши и клавишу слушателей; два независимая, а потому VisualComponent может делегировать свои обязательства по безопасности потоков двум базовым потокобезопасным спискам.
листинг 4.9. Делегирование безопасности потоков нескольким базовым переменным состояния.
VisualComponent использует CopyOnWriteArrayList для хранения каждого списка прослушивателей; это потокобезопасная реализация списка, особенно подходящая для управления списками прослушивателей (см. раздел 5.2.3). Каждый список является потокобезопасным, и потому что нет никаких ограничений соединение состояния одного с состоянием другого, VisualComponent может делегировать свои обязанности по безопасности потоков базовому mouseListeners и keyListeners объекты.
4.3.3. Когда Делегирование Не Удается
большинство составных классов не так просто, как VisualComponent : у них есть инварианты, которые связывают их переменные состояния компонента. NumberRange в листинге 4.10 используются два AtomicIntegers управлять своим состоянием, но накладывает дополнительное ограничение-что первое число должно быть меньше или равно второму.
листинг 4.10. Класс диапазона чисел, который недостаточно защищает свои инварианты. Не делай этого.
NumberRange и не потокобезопасна; он не сохраняет инвариант, который ограничивает нижний и верхний. The setLower и setUpper методы пытаются уважать этот инвариант, но делают это плохо. Оба!—23—> и setUpper последовательности проверки-после этого-действия, но они не делают используйте достаточную блокировку, чтобы сделать их атомарными. Если диапазон чисел имеет значение (0, 10), и один поток вызывает setLower(5) в то время как другой поток вызывает setUpper(4) , С некоторыми неудачными сроками оба пройдут проверки в сеттерах, и будут применены обе модификации. В результате диапазон теперь имеет значение (5, 4) —недопустимом состоянии. Так что пока основной AtomicIntegers являются потокобезопасными, сложных не. Потому что базовые переменные состояния lower и upper не являются независимыми, NumberRange нельзя просто делегировать безопасность потока его потокобезопасным переменным состояния.
NumberRange смогл быть сделано поток-безопасным путем использование фиксировать для поддержания своих инвариантов, как защищать нижний и верхний с общим замком. Он также должен избегать публикации нижнего и верхнего, чтобы клиенты не подрывали его инварианты.
если класс имеет составные действия, как NumberRange делает, делегирование в одиночку снова не подходит для безопасность потока. В этих случаях класс должен предоставить свою собственную блокировку, чтобы гарантировать, что составные действия являются атомарными, если только все составное действие не может быть делегировано базовым переменным состояния.
если класс состоит из нескольких независимых переменных состояния потокобезопасности и не имеет операций с недопустимыми переходами состояния, то он может делегировать безопасность потока базовым переменным состояния.