Какие функции делают класс безопасным для потоков?

В MSDN некоторые.NET-классы описываются следующим образом:

" Этот тип является потокобезопасным ".

или

" Публичные статические (Shared in Visual Basic) члены этого типа являются потокобезопасными. Члены экземпляра не гарантируются потокобезопасностью".

Мой вопрос в том, какие функции делают класс для потокобезопасности?

  • Существуют ли какие-либо стандарты, рекомендации или рекомендации по программированию по обеспечению безопасности потоков?

  • Когда я использую ключевое слово lock (С#), это означает, что мой класс является потокобезопасным или нет?

  • Как оценивать потокобезопасность класса? Есть ли какие-либо тесты, чтобы убедиться, что класс на 100% потокобезопасен?

Пример:

public class MyClass
{
    public void Method()
    {
        lock (this)
        {
            // Now, is my class 100% thread-safe like Microsoft classes?
        }
    }
    type m_member1;
    type m_member2;
}

благодаря

Ответ 1

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

Существует несколько способов сделать класс потокобезопасным:

  1. Сделайте его неизменным, если класс не содержит состояния, можно безопасно использовать одновременно несколько потоков.
  2. Используйте блокировку для уменьшения параллелизма. Однако это не является гарантией безопасности потоков, а просто гарантирует, что блок кода не будет выполняться одновременно несколькими потоками. Если состояние хранится между вызовами метода, это может все же стать непоследовательным.

Как создать потокобезопасный класс действительно зависит от того, что вы хотите делать с рассматриваемым классом.

Вам также нужно спросить себя, мне нужно сделать мой класс потокобезопасным? общей моделью большинства интерфейсов пользовательского интерфейса является то, что существует один поток пользовательского интерфейса. Например, в WinForms, WPF и Silverlight большая часть вашего кода будет выполнена из потока пользовательского интерфейса, что означает, что вам не нужно создавать потокобезопасность в своих классах.

Ответ 2

Существуют ли какие-либо стандарты, рекомендации или рекомендации по программированию по обеспечению безопасности потоков?

Самый важный стандарт - обеспечить, чтобы все статические элементы были потокобезопасными. Вы увидите, что все хорошо написанные API, включая библиотеку базового класса.NET, обеспечивают эту гарантию по всем направлениям. Для этого есть веская причина. Поскольку статические члены совместно используются в AppDomain, они могут использоваться многими различными потоками, даже если вы даже не осознаете это. Было бы неудобно в лучшем случае обеспечить вашу собственную синхронизацию для каждого доступа к статическому члену. Представьте себе, как это было бы, если бы Console.WriteLine не был потокобезопасным.

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

Прочитайте Threading в С# Джозефом Альбахари. Это один из лучших и наиболее проверенных ресурсов.

Когда я использую ключевое слово lock (С#), это означает, что мой класс является потокобезопасным или нет?

Неа! Нет волшебной пули, которая может сделать класс потокобезопасным. Ключевое слово lock - это лишь один из многих различных инструментов, которые можно использовать для обеспечения безопасности класса для одновременного доступа несколькими потоками. Но просто использование lock ничего не гарантирует. Это правильное использование механизмов синхронизации, обеспечивающих безопасность кода. Существует много способов использовать эти механизмы неправильно.

Как оценивать потокобезопасность класса? Есть ли какие-либо тесты, чтобы убедиться, что класс на 100% потокобезопасен?

Это вопрос в миллион долларов! Это невероятно трудно проверить многопоточный код. Инструмент CHESS, предоставленный Microsoft Research, является одной из попыток упростить жизнь для параллельных программистов.

Ответ 3

Прежде всего, не используйте lock (this).

Это может вызвать взаимоблокировки. Потому что другой код может блокировать тот же объект из-за пределов класса. Вы должны создать локальный объект и использовать его как блокировку класса.

Во-вторых, безопасность потоков - сложная проблема. Там тонны материала об этом в Интернете.

Как правило, все общедоступные методы должны быть заблокированы и потокобезопасны для того, чтобы класс был потокобезопасным.

Ответ 4

Класс считается потокобезопасным, если только один поток за раз может изменять состояние объектов, созданных из класса ИЛИ класс предоставляет такую функциональность, что несколько потоков могут одновременно вызвать различные методы класса.

Ответ 5

Когда я использую ключевое слово lock (С#), это означает, что мой класс является потокобезопасным или нет? Когда вы используете блокировку, это означает, что часть кода внутри блокировки {} является потокобезопасной. Это не гарантирует, что ваш класс является потокобезопасным. И поскольку Йохаи Тиммер сказал, что не стоит lock(this)

Как оценивать потокобезопасность класса? Есть ли какие-либо тесты, чтобы убедиться, что класс на 100% потокобезопасен? Я не уверен, что есть какие-либо тесты, потому что в многопоточности всегда возможно, что вы случайно получаете правильные результаты. Поэтому, чтобы быть уверенным, что вы можете пройти через код класса, чтобы убедиться, что он защищен потоками

Ответ 6

Очень простое объяснение: тип безопасного типа означает, что при использовании вашего типа вам не нужны дополнительные механизмы синхронизации. Скажем, вы можете создать экземпляр, передающий ссылку на другой поток (или несколько потоков), и использовать методы/свойства из обоих потоков без каких-либо дополнительных накладных расходов для обеспечения безопасности потоков.