Из Википедии, бесплатной энциклопедии
  (Перенаправлено из Thread-security )
Перейти к навигации Перейти к поиску

Безопасность потоков - это концепция компьютерного программирования, применимая к многопоточному коду. Поточно-безопасный код управляет только общими структурами данных таким образом, чтобы гарантировать, что все потоки ведут себя должным образом и выполняют свои проектные спецификации без непреднамеренного взаимодействия. Существуют различные стратегии создания потоковобезопасных структур данных. [1] [2]

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

Уровни безопасности потоков [ править ]

Программные библиотеки могут предоставить определенные гарантии безопасности потоков. Например, одновременное чтение может быть гарантировано потокобезопасным, а одновременная запись - нет. Является ли программа, использующая такую ​​библиотеку, потокобезопасной, зависит от того, использует ли она библиотеку в соответствии с этими гарантиями.

Различные поставщики используют немного разную терминологию для обеспечения безопасности потоков: [3] [4] [5] [6]

  • Потокобезопасность : при одновременном доступе нескольких потоков в реализации гарантируется отсутствие условий гонки .
  • Условно безопасный : разные потоки могут обращаться к разным объектам одновременно, а доступ к общим данным защищен от состояния гонки.
  • Не потокобезопасный : к структурам данных не должны одновременно обращаться разные потоки.

Гарантии безопасности потоков обычно также включают этапы проектирования для предотвращения или ограничения риска различных форм взаимоблокировок , а также оптимизацию для максимизации одновременной производительности. Однако гарантии отсутствия тупиков не всегда могут быть предоставлены, поскольку тупиковые ситуации могут быть вызваны обратными вызовами и нарушением архитектурного разделения независимо от самой библиотеки.

Подходы к реализации [ править ]

Ниже мы обсудим два класса подходов к предотвращению состояний гонки для обеспечения безопасности потоков.

Первый класс подходов направлен на предотвращение совместного использования состояния и включает:

Повторный вход
Написание кода таким образом, чтобы он мог частично выполняться потоком, выполняться тем же потоком или одновременно выполняться другим потоком и при этом правильно завершать исходное выполнение. Это требует сохранения информации о состоянии в переменных, локальных для каждого выполнения, обычно в стеке, а не в статических или глобальных переменных или другом нелокальном состоянии. Все нелокальные состояния должны быть доступны через атомарные операции, и структуры данных также должны быть реентерабельными.
Локальное хранилище потока
Переменные локализованы, поэтому каждый поток имеет свою собственную частную копию. Эти переменные сохраняют свои значения в пределах подпрограммы и других границ кода и являются потокобезопасными, поскольку они локальны для каждого потока, даже если код, который обращается к ним, может выполняться одновременно другим потоком.
Неизменяемые объекты
Состояние объекта не может быть изменено после постройки. Это означает, что совместно используются только данные только для чтения и обеспечивается внутренняя безопасность потоков. Затем можно реализовать изменяемые (неконстантные) операции таким образом, чтобы они создавали новые объекты вместо изменения существующих. Этот подход характерен для функционального программирования, а также используется строковыми реализациями в Java, C # и Python. (См. Неизменяемый объект .)

Второй класс подходов связан с синхронизацией и используется в ситуациях, когда нельзя избежать общего состояния:

Взаимное исключение
Доступ к общим данным сериализуется с использованием механизмов, которые гарантируют, что только один поток читает или записывает общие данные в любое время. Включение взаимных потребностей исключения быть хорошо продумано, так как неправильное использование может привести к побочным эффектам , как тупики , livelocks и ресурсный голод .
Атомарные операции
Доступ к общим данным осуществляется с помощью атомарных операций, которые не могут быть прерваны другими потоками. Обычно это требует использования специальных инструкций на машинном языке , которые могут быть доступны в библиотеке времени выполнения . Поскольку операции являются атомарными, общие данные всегда сохраняются в допустимом состоянии, независимо от того, как к ним обращаются другие потоки. Атомарные операции составляют основу многих механизмов блокировки потоков и используются для реализации примитивов взаимного исключения.

Примеры [ править ]

В следующей части Java коде Ключевое слово Java синхронизируются делает метод поточно-:

class  Counter  {  private  int  i  =  0 ; общедоступная  синхронизированная  void  inc ()  {  i ++ ;  } }

В языке программирования C у каждого потока есть свой стек. Однако статическая переменная не хранится в стеке; все потоки имеют к нему одновременный доступ. Если несколько потоков перекрываются при выполнении одной и той же функции, возможно, что статическая переменная может быть изменена одним потоком, в то время как другой находится на полпути к ее проверке. Эта сложная для диагностики логическая ошибка , которая может компилироваться и работать правильно большую часть времени, называется состоянием гонки . Один из распространенных способов избежать этого использовать другую общую переменную в качестве «замок» или «мьютекс» (от MUT UAL экс ключения).

В следующем фрагменте кода C функция является поточно-ориентированной, но не реентерабельной:

# включить <pthread.h>int  increment_counter  () {  статический  счетчик int  = 0 ; статический pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;        // разрешаем только одному потоку увеличиваться за раз  pthread_mutex_lock ( & mutex ); ++ счетчик ; // сохраняем значение перед тем, как другие потоки увеличивают его дальше  int  result  =  counter ; pthread_mutex_unlock ( & mutex ); вернуть  результат ; }

В приведенном выше примере, increment_counterможет вызываться разными потоками без каких-либо проблем, поскольку мьютекс используется для синхронизации всего доступа к общей counterпеременной. Но если функция используется в повторно входимом обработчике прерывания и возникает второе прерывание, когда мьютекс заблокирован, вторая процедура зависнет навсегда. Поскольку обслуживание прерывания может отключить другие прерывания, может пострадать вся система.

Одна и та же функция может быть реализована как поточно-ориентированной, так и повторно входимой, используя безблокировочную атомику в C ++ 11 :

# включить <атомарный>int  increment_counter  () {  статический  std :: atomic < int >  счетчик ( 0 ); // приращение гарантированно выполняется атомарно  int  result  =  ++ counter ; вернуть  результат ; }

См. Также [ править ]

  • Контроль параллелизма
  • Исключительная безопасность
  • Инверсия приоритета
  • ThreadSafe

Ссылки [ править ]

  1. ^ Керриск, Майкл (2010). Интерфейс программирования Linux . Пресс без крахмала . п. 655.
  2. ^ "Руководство по многопоточному программированию" . Корпорация Oracle . Ноябрь 2010 г. Процедура является потокобезопасной, если процедура логически корректна при одновременном выполнении несколькими потоками.
  3. ^ "Повторная входимость и безопасность потоков | Qt 5.6" . Qt Project . Проверено 20 апреля 2016 .
  4. ^ "ip :: tcp - 1.51.0" . Boost.org . Проверено 16 октября 2013 .
  5. ^ "Классификация безопасности потоков API" . Publib.boulder.ibm.com. 1998-06-09 . Проверено 16 октября 2013 .[ мертвая ссылка ]
  6. ^ «Уровни безопасности интерфейса MT - Руководство по многопоточному программированию» . Docs.oracle.com. 2010-11-01 . Проверено 16 октября 2013 .

Внешние ссылки [ править ]

  • Эксперты по Java Q&A (20 апреля 1999 г.). «Поточно-ориентированный дизайн (20.04.1999)» . JavaWorld.com . Проверено 22 января 2012 .
  • TutorialsDesk (30 сентября 2014 г.). «Учебное пособие по синхронизации и безопасности потоков с примерами на Java» . TutorialsDesk.com . Проверено 22 января 2012 .
  • Веннерс, Билл (1 августа 1998 г.). «Дизайн для обеспечения безопасности потоков» . JavaWorld.com . Проверено 22 января 2012 .
  • Зьюсс, Майкл (15 октября 2006 г.). «Краткое руководство по обеспечению безопасности потоков» . Параллельное мышление . Проверено 22 января 2012 .