Недавно я попытался получить доступ к текстовому полю из потока (кроме потока пользовательского интерфейса), и возникло исключение. В нем что-то говорилось о том, что «код не является потокобезопасным», и поэтому я написал делегат (помог образец из MSDN) и вместо этого вызвал его.
Но даже в этом случае я не совсем понимал, зачем нужен весь дополнительный код.
Обновление: столкнусь ли я с серьезными проблемами, если проверю
Controls.CheckForIllegalCrossThread..blah =true
multithreading
thread-safety
definition
Вивек Бернар
источник
источник
Race-Condition
Ответы:
У Эрика Липперта есть хороший пост в блоге, озаглавленный « Что вы называете« потокобезопасным »? об определении безопасности потоков, найденном в Википедии.
3 важные вещи, извлеченные из ссылок:
Определенно стоит прочитать!
источник
Проще говоря, потокобезопасность означает, что доступ к нему безопасен из нескольких потоков. Когда вы используете несколько потоков в программе, и каждый из них пытается получить доступ к общей структуре данных или месту в памяти, может произойти несколько плохих вещей. Итак, вы добавляете дополнительный код, чтобы предотвратить эти плохие вещи. Например, если два человека писали один и тот же документ в одно и то же время, второй человек, который должен сохранить, перезапишет работу первого человека. Чтобы сделать его потокобезопасным, вы должны заставить человека 2 ждать, пока человек 1 выполнит свою задачу, прежде чем позволить человеку 2 редактировать документ.
источник
В Википедии есть статья о безопасности потоков.
Эта страница определений (вы должны пропустить рекламу - извините) определяет ее следующим образом:
Поток - это путь выполнения программы. Однопоточная программа будет иметь только один поток, поэтому этой проблемы не возникает. Практически все программы с графическим интерфейсом пользователя имеют несколько путей выполнения и, следовательно, потоков - их как минимум два, один для обработки отображения графического интерфейса и обработки пользовательского ввода, и, по крайней мере, один другой для фактического выполнения операций программы.
Это сделано для того, чтобы пользовательский интерфейс оставался отзывчивым, пока программа работает, за счет разгрузки любого длительного процесса в любые потоки, не связанные с пользовательским интерфейсом. Эти потоки могут быть созданы один раз и существовать на протяжении всего времени существования программы или просто создаваться при необходимости и уничтожаться по завершении.
Поскольку этим потокам часто требуется выполнять общие действия - ввод-вывод диска, вывод результатов на экран и т. Д., - эти части кода должны быть написаны таким образом, чтобы они могли обрабатывать вызовы из нескольких потоков, часто в в то же время. Это будет включать такие вещи, как:
источник
Проще говоря, потокобезопасность означает, что метод или экземпляр класса могут использоваться несколькими потоками одновременно без каких-либо проблем.
Рассмотрим следующий метод:
Теперь поток A и поток B хотят выполнить AddOne (). но A запускается первым и считывает значение myInt (0) в tmp. Теперь по какой-то причине планировщик решает остановить поток A и отложить выполнение до потока B. Теперь поток B также считывает значение myInt (все еще 0) в свою собственную переменную tmp. Поток B завершает весь метод, поэтому в итоге myInt = 1. И возвращается 1. Теперь снова очередь потока А. Тема A продолжается. И добавляет 1 к tmp (tmp было 0 для потока A). А затем сохраняет это значение в myInt. myInt снова равен 1.
Итак, в этом случае метод AddOne был вызван два раза, но поскольку метод не был реализован потокобезопасным способом, значение myInt равно не 2, как ожидалось, а 1, потому что второй поток прочитал переменную myInt до завершения первого потока. обновляя его.
В нетривиальных случаях создавать потокобезопасные методы очень сложно. А техник довольно много. В Java вы можете пометить метод как синхронизированный, это означает, что только один поток может выполнять этот метод в данный момент. Остальные потоки ждут своей очереди. Это делает метод потокобезопасным, но если в методе необходимо выполнить много работы, это приводит к потере много места. Другой метод - «пометить только небольшую часть метода как синхронизированную».путем создания блокировки или семафора и блокировки этой небольшой части (обычно называемой критической частью). Существуют даже некоторые методы, которые реализованы как потокобезопасные без блокировки, что означает, что они построены таким образом, что несколько потоков могут проходить через них одновременно, не вызывая проблем, это может быть случай, когда метод только выполняет один атомарный вызов. Атомарные вызовы - это вызовы, которые нельзя прервать и которые могут выполняться только одним потоком за раз.
источник
В реальном мире пример для непрофессионала
Предположим, у вас есть банковский счет с интернет-банкингом и мобильным банкингом, а на вашем счете всего 10 долларов. Вы выполнили перевод баланса на другой счет с помощью мобильного банкинга, а тем временем вы совершали покупки в Интернете, используя тот же банковский счет. Если этот банковский счет не является потокобезопасным, тогда банк позволяет вам выполнять две транзакции одновременно, и тогда банк станет банкротом.
Threadsafe означает, что состояние объекта не изменяется, если одновременно несколько потоков пытаются получить доступ к объекту.
источник
Вы можете получить более подробное объяснение из книги «Java Concurrency in Practice»:
источник
Модуль является потокобезопасным, если он гарантирует, что может поддерживать свои инварианты перед лицом многопоточного и параллельного использования.
Здесь модуль может быть структурой данных, классом, объектом, методом / процедурой или функцией. В основном ограниченный фрагмент кода и связанные данные.
Гарантия потенциально может быть ограничена определенными средами, такими как конкретная архитектура ЦП, но должна действовать для этих сред. Если нет явного разграничения сред, то обычно подразумевается, что это справедливо для всех сред, в которых код может быть скомпилирован и выполнен.
Модули, небезопасные для потоков, могут правильно работать при многопоточном и одновременном использовании, но это часто больше зависит от удачи и совпадения, чем от тщательного проектирования. Даже если какой-то модуль у вас не сломается, он может сломаться при перемещении в другое окружение.
Ошибки многопоточности часто трудно отлаживать. Некоторые из них случаются лишь изредка, другие проявляются агрессивно - это тоже может быть связано с окружающей средой. Они могут проявляться как слегка неверные результаты или тупиковые ситуации. Они могут непредсказуемым образом испортить структуры данных и вызвать появление других, казалось бы, невозможных ошибок в других удаленных частях кода. Он может быть очень специфичным для конкретного приложения, поэтому дать общее описание сложно.
источник
Безопасность потоков : потокобезопасная программа защищает данные от ошибок согласованности памяти. В многопоточной программе потокобезопасная программа не вызывает каких-либо побочных эффектов при выполнении нескольких операций чтения / записи из нескольких потоков над одними и теми же объектами. Различные потоки могут совместно использовать и изменять данные объекта без ошибок согласованности.
Вы можете добиться безопасности потоков, используя расширенный API параллелизма. На этой странице документации представлены хорошие программные конструкции для обеспечения безопасности потоков.
Объекты блокировки поддерживают идиомы блокировки, которые упрощают работу многих параллельных приложений.
Исполнители определяют API высокого уровня для запуска и управления потоками. Реализации исполнителя, предоставляемые java.util.concurrent, обеспечивают управление пулом потоков, подходящее для крупномасштабных приложений.
Параллельные коллекции упрощают управление большими коллекциями данных и могут значительно снизить потребность в синхронизации.
У атомарных переменных есть функции, которые минимизируют синхронизацию и помогают избежать ошибок согласованности памяти.
ThreadLocalRandom (в JDK 7) обеспечивает эффективную генерацию псевдослучайных чисел из нескольких потоков.
Обратитесь к пакетам java.util.concurrent и java.util.concurrent.atomic, чтобы узнать о других конструкциях программирования.
источник
Вы явно работаете в среде WinForms. Элементы управления WinForms демонстрируют сходство потоков, что означает, что поток, в котором они созданы, является единственным потоком, который можно использовать для доступа к ним и их обновления. Вот почему вы найдете примеры в MSDN и в других местах, демонстрирующие, как маршалировать вызов обратно в основной поток.
Обычная практика WinForms - иметь один поток, посвященный всей вашей работе с пользовательским интерфейсом.
источник
Я нахожу концепцию http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 тем, что я обычно считаю небезопасной потоковой передачей, когда метод имеет побочный эффект, такой как глобальная переменная, и полагается на него.
Например, я видел код, который преобразовывал числа с плавающей запятой в строку, если два из них запускаются в разных потоках, глобальное значение decimalSeparator может быть навсегда изменено на '.'
источник
Чтобы понять безопасность потоков, прочитайте разделы ниже :
источник