Читаем Язык программирования C#9 и платформа .NET5 полностью

Пространство имен System.Threading появилось в версии .NET 1.0 и предлагает один из подходов к построению многопоточных приложений. Равным типом в этом пространстве имен можно назвать, пожалуй, класс Thread, поскольку он представляет отдельный поток. Если необходимо программно получить ссылку на поток, который в текущий момент выполняет заданный член, то нужно просто обратиться к статическому свойству Thread.CurrentThread:


static void ExtractExecutingThread()

{

  // Получить поток, который в настоящий момент выполняет данный метод.

  Thread currThread = Thread.CurrentThread;

}


Вспомните, что в .NET Core существует только один домен приложения. Хотя создавать дополнительные домены приложений нельзя, домен приложения может иметь многочисленные потоки, выполняющиеся в каждый конкретный момент времени. Чтобы получить ссылку на домен приложения, который обслуживает приложение, понадобится вызвать статический метод Thread.GetDomain():


static void ExtractAppDomainHostingThread()

{

  // Получить домен приложения, обслуживающий текущий поток.

  AppDomain ad = Thread.GetDomain();

}


Одиночный поток в любой момент также может быть перенесен в контекст выполнения и перемещаться внутри нового контекста выполнения по прихоти среды .NET Core Runtime. Для получения текущего контекста выполнения, в котором выполняется поток, используется статическое свойство Thread.CurrentThread.ExecutionContext:


static void ExtractCurrentThreadExecutionContext()

{

  // Получить контекст выполнения, в котором работает текущий поток.

  ExecutionContext ctx =

    Thread.CurrentThread.ExecutionContext;

}


Еще раз: за перемещение потоков в контекст выполнения и из него отвечает среда .NET Core Runtime. Как разработчик приложений .NET Core, вы всегда остаетесь в блаженном неведении относительно того, где завершается каждый конкретный поток. Тем не менее, вы должны быть осведомлены о разнообразных способах получения лежащих в основе примитивов.

Сложность, связанная с параллелизмом

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

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

Чтобы проиллюстрировать проблему, давайте предположим, что поток вызывает метод специфичного объекта. Теперь представим, что поток приостановлен планировщиком потока, чтобы позволить другому потоку обратиться к тому же методу того же самого объекта.

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

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

Роль синхронизации потоков

К настоящему моменту должно быть ясно, что многопоточные программы сами по себе довольно изменчивы, т.к. многочисленные потоки могут оперировать разделяемыми ресурсами (более или менее) одновременно. Чтобы защитить ресурсы приложений от возможного повреждения, разработчики приложений .NET Core должны применять потоковые примитивы (такие как блокировки, мониторы, атрибут [Synchronization] или поддержка языковых ключевых слов) для управления доступом между выполняющимися потоками.

Перейти на страницу:

Похожие книги

Programming with POSIX® Threads
Programming with POSIX® Threads

With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications. The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O. This book offers an in-depth description of the IEEE operating system interface standard, POSIX (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset. Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.

David Butenhof

Программирование, программы, базы данных
Разработка ядра Linux
Разработка ядра Linux

В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux. Ядро рассматривается как с теоретической, так и с прикладной точек зрения, что может привлечь читателей различными интересами и потребностями.Книга может быть рекомендована как начинающим, так и опытным разработчикам программного обеспечения, а также в качестве дополнительных учебных материалов.

Роберт Лав

Программирование, программы, базы данных / Программирование / Книги по IT
C++
C++

С++ – это универсальный язык программирования, задуманный так, чтобы сделать программирование более приятным для серьезного программиста. За исключением второстепенных деталей С++ является надмножеством языка программирования C. Помимо возможностей, которые дает C, С++ предоставляет гибкие и эффективные средства определения новых типов. Используя определения новых типов, точно отвечающих концепциям приложения, программист может разделять разрабатываемую программу на легко поддающиеся контролю части. Такой метод построения программ часто называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. Такие объекты просты и надежны в использовании в тех ситуациях, когда их тип нельзя установить на стадии компиляции. Программирование с применением таких объектов часто называют объектно-ориентированным. При правильном использовании этот метод дает более короткие, проще понимаемые и легче контролируемые программы. Ключевым понятием С++ является класс. Класс – это тип, определяемый пользователем. Классы обеспечивают сокрытие данных, гарантированную инициализацию данных, неявное преобразование типов для типов, определенных пользователем, динамическое задание типа, контролируемое пользователем управление памятью и механизмы перегрузки операций. С++ предоставляет гораздо лучшие, чем в C, средства выражения модульности программы и проверки типов. В языке есть также усовершенствования, не связанные непосредственно с классами, включающие в себя символические константы, inline-подстановку функций, параметры функции по умолчанию, перегруженные имена функций, операции управления свободной памятью и ссылочный тип. В С++ сохранены возможности языка C по работе с основными объектами аппаратного обеспечения (биты, байты, слова, адреса и т.п.). Это позволяет весьма эффективно реализовывать типы, определяемые пользователем. С++ и его стандартные библиотеки спроектированы так, чтобы обеспечивать переносимость. Имеющаяся на текущий момент реализация языка будет идти в большинстве систем, поддерживающих C. Из С++ программ можно использовать C библиотеки, и с С++ можно использовать большую часть инструментальных средств, поддерживающих программирование на C. Эта книга предназначена главным образом для того, чтобы помочь серьезным программистам изучить язык и применять его в нетривиальных проектах. В ней дано полное описание С++, много примеров и еще больше фрагментов программ.

Мюррей Хилл , Бьёрн Страуструп , Бьярн Страустрап

Программирование, программы, базы данных / Программирование / Книги по IT