Какие программы поддерживают многопоточность

Содержание

Для того, чтобы успешно строить карьеру программиста, необходимо устроиться работать по соответствующей профессии, а также знать особенности языков программирования. Огромным спросом у разработчиков на данный момент пользуется Java. Это – кроссплатформенный универсальный вариант «общения» с компьютерами и программным обеспечением. Прост в освоении, обладает относительно понятным синтаксисом. Многофункционален, имеет возможность ООП.

Когда будущий разработчик проходит собеседование, ему задают разнообразные вопросы по коддингу. В случае с Java немаловажным моментом является тема потоков. Особенно многопоточности. Данная статья поможет разобраться в соответствующем направлении, а также составить приложение, использующее Java Concurrency.

Процесс – определение

Рассматривая упомянутую тему, нельзя обойти стороной такое понятие как «процесс». Это – основа, на которой базируется многопоточность.

Каждый программист должен уяснить следующее:

  1. Процесс представляет сочетание кода и информации. Он создается ОС при запуске приложения. Служит виртуальным адресным пространством.
  2. Процессы на задействованном устройстве функционируют обособленно друг от друга.
  3. Нет прямого доступа к общей информации в других процессах, работающих на девайсе.
  4. Для успешной работы требуется выделение тех или иных ресурсов – памяти и времени. Эти задачи возлагаются непосредственно на операционную систему.
  5. Если один из процессов блокируется, новый не может работать. Это происходит до тех пор, пока первый, заблокированный, не будет разлочен.
  6. Для создания очередного нового процесса принято использовать родительские. В ходе реализации поставленной задачи будет проведено дублирование.
  7. Process-родитель умеет контролировать дочерние операции. Обратная связь невозможна ни при каких обстоятельствах.

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

Разбираемся в multithreading на C++

Потоки – что это и с чем их едят

В Java поток – это единица реализации программного кода. Последовательность данных, которая могут работать параллельно с другими своими «аналогами».

Поток отвечает за выполнение инструкций запущенного процесса, к которому он относится. Все это происходит параллельно с иными потоками этого же process. Является легковесным. Может «общаться» с другими потоками. Для реализации поставленной задачи требуется применение специальных методов.

Какими могут быть потоки – классификация

Собеседование по Java и многопоточности обязательно предусматривает вопросы по «обычным» потокам в программировании. Стоит классифицировать оные. Это помогает разобраться, за что отвечает тот или иной «вариант».

Существует разделение потоков по типу движения информации:

  • вводные – информация поступает в утилиту, после чего считывается;
  • выводные – программа передает те или иные сведения, осуществляется запись в потоки.

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

[C++11] STL: Thread — Многопоточные программы

У каждого приведенного примера существуют собственные абстрактные классы.

Принципы работы потоков

Перед использованием в Java многопоточности, нужно понимать, как будет работать каждая такая «операция». Многое зависит от того, какие манипуляции реализовываются. Чаще всего имеет место чтение и запись.

В Java потоки будут обладать примерно таким алгоритмом:

  1. Создается экземпляр необходимого потока.
  2. Последний открывается для дальнейшего считывания. При необходимости – для записи новой информации.
  3. Пользователь проводит задуманные изначально действия. В предложенном примере – чтение и запись информации.
  4. Осуществляется закрытие потока.

Создание и открытие экземпляра – это единый шаг. Остальные действия не реализовываются одновременно. Они воплощаются в жизнь последовательно.

Чем хороши потоки

В процессе программирования можно использовать различные элементы и операции. Потоки в Java имеют ряд преимуществ. К ним относят:

  1. Относительную легкость по сравнению с процессами. Это позволяет минимизировать ресурсные затраты для функционирования приложения.
  2. Быстрое переключение софта.
  3. Упрощенную схему взаимодействия процессов между собой.

У мелких утилит есть всего одна «нить». Это – главная нить (main thread). Дополнительно могут запускаться иные потоки. Они будут носить название дочерних. Главный thread отвечает за выполнение метода main, после чего завершается.

Определение многопоточности

Многопоточность Java – это поддержка одновременной работы более одного потока. В процессе выполнения приложения некоторые «операции» осуществляются параллельно друг другу, да еще и в «фоновом» режиме. Наглядные примеры:

  • сигнальная обработка;
  • операции с памятью;
  • управление системой устройства/софта.

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

Важно: многопоточность не имеет места с процессорами одноядерного типа. Там время процессорного характера делится между несколькими процессами и «открытыми» потоками.

Потоковая синхронизация – как понимать?

Определение синхронизации потоков имеет прямое отношение к многопоточности. Синхронизированный «участок» программного кода выполняется только одним потоком одновременно.

В Java присутствует поддержка одновременного выполнения нескольких подобных «элементов». Соответствующее явление иногда приводит к тому, что больше одного потока имеет доступ к одним и тем же полям/объектам.

Синхронизация – выполнение параллельных потоков в приложении синхронно. Способствует избеганию ошибок согласования памяти. При объявлении метода синхронизированным нить держит монитор для объекта. Если иной поток займется исполнением синхронизированного метода, первый будет блокирован.

Синхронизацию в Java реализовывают через зарезервированное слово synchronized. Он может применяться в классах для определения синхронизированных:

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

Потоковые состояния

Thread в Java встречается в нескольких состояниях:

  • new – создан;
  • runnable – запуск;
  • blocked – блокировка;
  • terminated – завершение;
  • waiting – ожидание.

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

Также можно встретить Suspend. Это процесс приостановки работающего потока. Предусматривает продолжение с момента «паузы». Состояние Dead в Java возникает при полном прекращении работы Thread. Указывает на то, что жизненный цикл «объекта» подошел к концу.

Concurrency – библиотека для работы со Threads

У Джавы немало документации на русском языке, при помощи которой можно разобраться в принципах работы с языком. И там обязательно рассказывается о многопоточности. В процессе чтения соответствующей информации программеры встречают такое понятие как Concurrency.

Так называют специальную библиотеку Java. В ней собраны спецклассы, предназначенные для работы с несколькими нитями. Они включены в пакет java.util.concurren. Включают в себя различные элементы:

  1. Concurrent Collections – коллекции, предназначающиеся для работы с многопоточностью. В процессе работа используется принцип блокировки по сегментам информации. Возможна оптимизация параллельного чтения по wait-free алгоритмизации.
  2. Synchronizers – вспомогательный контент. Задействуется непосредственно при синхронизации потоковой информации. Особо важен для параллельных вычислений.
  3. Queues – очереди блокирующего и неблокирующего характера для многопоточности. Первый вариант применяет для «тормоза» потоков, если не проходят реализацию те или иные условия. Второй актуален для обеспечения скорости обработки информации. Функционирование в данном случае будет осуществляться без потоковой блокировки.
  4. Executions – фреймворки, использующиеся для создания потоковых пулов, а также при планировании асинхронных задач, для которых нужно выводить результаты.
  5. Locks – альтернативные способы синхронизации.
  6. Atomics – классы, поддерживающие атомарные операции со ссылками/различными примитивами.

Каждый «пакет» имеет собственные классы Java. Они отвечают за те или иные манипуляции при коддинге. Полную информацию о них можно изучить по этой ссылке.

Как создавать потоки: способы реализации

Пока не рассмотрены примеры многопоточности в языке Java, стоит уяснить, каким образом создаются threads. Существуют различные варианты развития событий. Все зависит от того, какие задачи предстоит реализовывать.

Создание потоковых «элементов» возможно через:

  • класс, реализующий Runnable;
  • классы, расширяющие Thread;
  • реализацию java.util.concurrent.Callable.
Читайте также:
Программа для печати в размер

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

Метод Runnable

На практике все перечисленные способы создания threads не слишком трудно реализовать. В случае с Runnable потребуется:

  • создать объект класса thread;
  • сделать class object, который реализовывает интерфейс Runnable;
  • вызвать метод start() у объекта thread.

Все это поможет сделать new thread, а затем использовать его.

Метод Thread

Еще один вариант – наследование. Для этого предстоит:

  • сделать class object ClassName extends Thread;
  • обеспечить предопределение run() в соответствующем классе.

Позже будет приведен пример, в котором осуществляется передача имени потока «Second»

Через Concurrent

В этом случае потребуется:

  • сделать объект класса, работающего с интерфейсом Callable;
  • обеспечить создание ExecutorService, в котором пользователь указывает пул потокового характера;
  • создать Future object.

Последний шаг осуществляется путем внедрения метода submit.

Наглядные примеры

Вот коды, которые пишем для создания new threads:

Если же нужно применять Callable, стоит обратить внимание на следующую кодификацию:

Для синхронизации методов можно реализовывать следующий код:

Для многих программистов при начале изучения многопоточных «элементов» Java становится проблемой принудительная остановка. На самом деле добиться желаемого результата не так трудно.

О принудительной остановке Thread

В Java 8 отсутствуют методы, при помощи которых можно добиться принудительной остановки. Но можно воспользоваться специальным механизмом, который позволяет вмешаться в потоковые процессы. Достаточно использовать interruption e. Это – механизм потокового оповещения.

У Thread есть булево поле – флаг прерывания. Устанавливается через вызов interrupt(). Проверить факт его задействования можно несколькими методами:

  • через bool isInterrupted() потокового объекта;
  • используя bool Thread.interruped().

В первом случае происходит возврат флага и его сброс. Во втором вызов осуществляется внутри thread, из которого был вызван метод. Данный прием дает возможность проверки состояния потокового прерывания в Java.

Здесь происходит следующее:

  1. В методе main() создается объект класса JoinClass, запускаемый через run.
  2. Происходит проверка на факт завершения. Каждые 100 секунд на экран выводится информация о значении счетчика.
  3. Главный метод ждет 1 000 мс для того, чтобы счетчик мог произвести расчеты.
  4. Осуществляется вызов interrupt у JoinClass.
  5. В цикле обнаруживается исключение.
  6. В разделе catch активируется return.

По принудительной потоковой остановке тоже много документации, как и по Java Concurrency гайдов на русском.

Как лучше понять многопоточность – совет не только новичкам

Для того, чтобы такие понятия, как interruptedexception e, multithreading (многопоточность) и процессы не доставляли хлопот, стоит выбрать грамотную методику обучения. Лучшим решением сегодня является посещение специализированных курсов. После них пройти собеседование (interview) по Java не составит никакого труда.

Пользователи могут выбрать специализацию и направление, в котором работать. Есть предложения для тех, кто только начал путь изучения программирования, а также для продвинутых юзеров. С их помощью познать Java Concurrency на практике не составит никакого труда, ведь процесс обучения контролируется опытными кураторами. В конце выдается сертификат установленного образца. Все лекции на русском.

Преимущества подобного подхода:

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

Это – отличный старт для программиста-новичка, а также для «любителей», предпочитающих самообразование.

Источник: otus.ru

Реализация многопоточности на языке C с помощью функций Win32

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

В MSVC существует несколько способов программирования с несколькими потоками: можно использовать C++/WinRT и библиотеку среда выполнения Windows, библиотеку Microsoft Foundation Class (MFC), C++/CLI и среду выполнения .NET, библиотеку времени выполнения C и API Win32. Эта статья посвящена многопоточности в C. Пример кода см . в разделе Пример многопоточной программы на языке C.

Многопоточные программы

Поток — это, по сути, путь к выполнению через программу. Это также наименьшая единица выполнения, которую планирует Win32. Поток состоит из стека, состояния регистров ЦП и записи в списке выполнения системного планировщика. Каждый поток совместно использует все ресурсы процесса.

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

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

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

Поддержка многопоточности библиотеками

Все версии CRT теперь поддерживают многопоточность, за исключением версий некоторых функций без блокировки. Дополнительные сведения см. в разделе Производительность многопоточных библиотек. Сведения о версиях CRT, доступных для связывания с кодом, см. в разделе Функции библиотеки CRT.

Включаемые файлы для многопоточности

Стандартные файлы CRT объявляют функции библиотеки времени выполнения C по мере их реализации в библиотеках. Если параметры компилятора указывают соглашения о вызовах __fastcall или __vectorcall , компилятор предполагает, что все функции должны вызываться с помощью соглашения о вызовах регистра. Функции библиотеки времени выполнения используют соглашение о вызовах C, а объявления в стандартных файлах включения предписывают компилятору создавать правильные внешние ссылки на эти функции.

Функции CRT для управления потоками

Все программы Win32 имеют по крайней мере один поток. Любой поток может создавать дополнительные потоки. Поток может быстро завершить свою работу, а затем завершить работу, или он может оставаться активным в течение всего срока действия программы.

Библиотеки CRT предоставляют следующие функции для создания и завершения потоков: _beginthread, _beginthreadex, _endthread и _endthreadex.

Функции _beginthread и _beginthreadex создают новый поток и возвращают идентификатор потока, если операция выполнена успешно. Поток завершается автоматически после завершения выполнения. Кроме того, он может завершиться вызовом _endthread или _endthreadex .

При вызове подпрограмм времени выполнения C из программы, созданной с помощью libcmt.lib, необходимо запустить потоки с _beginthread помощью функции или _beginthreadex . Не используйте функции ExitThread Win32 и CreateThread . Использование SuspendThread может привести к взаимоблокировке, когда несколько потоков блокируются в ожидании завершения доступа приостановленного потока к структуре данных среды выполнения C.

Функции _beginthread и _beginthreadex

Функции _beginthread и _beginthreadex создают новый поток. Поток совместно использует сегменты кода и данных процесса с другими потоками в процессе, но имеет собственные уникальные значения регистра, пространство стека и текущий адрес инструкции. Система предоставляет время ЦП каждому потоку, чтобы все потоки в процессе могли выполняться одновременно.

_beginthread и _beginthreadex похожи на функцию CreateThread в API Win32, но имеют следующие отличия:

  • Они инициализируют определенные переменные библиотеки времени выполнения C. Это важно, только если в потоках используется библиотека времени выполнения C.
  • CreateThread помогает обеспечить контроль над атрибутами безопасности. Эту функцию можно использовать для запуска потока в приостановленном состоянии.

_beginthread и _beginthreadex возвращают дескриптор в новый поток в случае успешного выполнения или код ошибки, если произошла ошибка.

Функции _endthread и _endthreadex

Функция _endthread завершает поток, созданный с помощью _beginthread (и аналогично завершает поток, _endthreadex созданный ). _beginthreadex Потоки завершаются автоматически по завершении. _endthread и _endthreadex полезны для условного завершения из потока. Например, поток, выделенный для обработки данных, может завершить работу, если ему не удается получить контроль над портом связи.

Написание многопоточной программы Win32

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

Совместное использование общих ресурсов между потоками

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

Читайте также:
Сколько каскадов в произвольной программе

Если несколько потоков обращаются к статическим данным, программа должна обеспечить возможные конфликты ресурсов. Рассмотрим программу, в которой один поток обновляет статическую структуру данных, содержащую координаты x,y для элементов, отображаемых другим потоком. Если поток обновления изменяет координату x и вытесняется перед изменением координаты y , поток отображения может быть запланирован до обновления координаты y . Элемент будет отображаться в неправильном расположении. Эту проблему можно избежать, используя семафоры для управления доступом к структуре.

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

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

Программа Bounce.c, показанная в примере многопоточной программы C, использует мьютекс с именем ScreenMutex для координации обновлений экрана. Каждый раз, когда один из потоков отображения готов к записи на экран, он вызывает WaitForSingleObject с дескриптором ScreenMutex и константой INFINITE, чтобы указать, что WaitForSingleObject вызов должен блокироваться на мьютексе, а не истекать время ожидания. Если ScreenMutex параметр не задан, функция ожидания задает мьютекс, чтобы другие потоки не могли вмешиваться в отображение, и продолжает выполнение потока. В противном случае поток блокируется до тех пор, пока мьютекс не будет очищен. Когда поток завершает обновление дисплея, он освобождает мьютекс, вызывая ReleaseMutex .

Экранные дисплеи и статические данные — это только два ресурса, требующих тщательного управления. Например, программа может иметь несколько потоков, обращаюющихся к одному файлу. Так как другой поток мог переместить указатель на файл, каждый поток должен сбросить указатель на файл перед чтением или записью. Кроме того, каждый поток должен убедиться, что он не вытеснен между временем, когда он размещает указатель, и временем доступа к файлу. Эти потоки должны использовать семафор для координации доступа к файлу, закрепив каждый доступ к файлу с WaitForSingleObject помощью вызовов и ReleaseMutex . Следующий пример кода иллюстрирует этот метод:

HANDLE hIOMutex = CreateMutex (NULL, FALSE, NULL); WaitForSingleObject( hIOMutex, INFINITE ); fseek( fp, desired_position, 0L ); fwrite( data, sizeof( data ), 1, fp ); ReleaseMutex( hIOMutex);

Стеки потоков

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

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

Потоки, которые вызывают библиотеку времени выполнения C или API Win32, должны иметь достаточно места в стеке для библиотеки и функций API, которые они вызывают. Для функции C printf требуется более 500 байт пространства стека, а при вызове процедур API Win32 должно быть доступно 2 КБ пространства стека.

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

Win32 также предоставляет локальное хранилище потоков (TLS) для хранения данных для каждого потока. Дополнительные сведения см. в разделе Локальное хранилище потоков (TLS).

Устранение потенциальных проблем при работе с многопоточными программами

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

Источник: learn.microsoft.com

10. Лекция: Потоки (threads) и многопоточное выполнение программ (multi-threading)

В лекции рассматриваются понятие потока (thread) и многопоточное выполнение (multi-threading); модели многопоточности; пользовательские потоки и потоки ядра; потоки в «Эльбрусе», Solaris, Linux, POSIX, Windows 2000, Java.

  • Введение
  • Однопоточные и многопоточные процессы
  • История многопоточности
  • Пользовательские потоки и потоки ядра
  • Проблемы многопоточности
  • Потоки POSIX (Pthreads)
  • Потоки и процессы в Solaris
  • Потоки в Windows 2000
  • Потоки в Linux
  • Потоки в Java
  • Ключевые термины
  • Краткие итоги
  • Набор для практики
  • Вопросы
  • Упражнения
  • Темы для курсовых работ, рефератов, эссе

Введение Многопоточность (multi-threading) – одна из наиболее интересных и актуальных тем в данном курсе и, по-видимому, в области ИТ вообще, и, кроме того, одна из излюбленных тем автора. Актуальность данной темы особенно велика, в связи с широким распространением многоядерных процессоров. В лекции рассмотрены следующие вопросы:

  • Исторический обзор многопоточности
  • Модели многопоточного исполнения
  • Проблемы, связанные с потоками
  • Потоки в POSIX (Pthreads)
  • Потоки в Solaris 2
  • Потоки в Windows 2000/XP
  • Потоки в Linux
  • Потоки в Java и .NET.

Однопоточные и многопоточные процессы К сожалению, до сих пор мышление многих программистов при разработке программ остается чисто последовательным. Не учитываются широкие возможности параллелизма, в частности, многопоточности. Последовательный (однопоточный) процесс – это процесс, который имеет только один поток управления (control flow), характеризующийся изменением его счетчика команд. Поток (thread) – это запускаемый из некоторого процесса особого рода параллельный процесс, выполняемый в том же адресном пространстве, что и процесс-родитель. Схема организации однопоточного и многопоточного процессов изображена на рис. 10.1. Рис. 10.1. Однопоточный и многопоточный процессы. Как видно из схемы, однопоточный процесс использует, как обычно, код, данные в основной памяти и файлы, с которыми он работает. Процесс также использует определенные значения регистров и стек, на котором исполняются его процедуры. Многопоточный процесс организован несколько сложнее. Он имеет несколько параллельных потоков, для каждого из которых ОС создает свой стек и хранит свои собственные значения регистров. Потоки работают в общей основной памяти и используют то же адресное пространство, что и процесс-родитель, а также разделяют код процесса и файлы. Многопоточность имеет большие преимущества:

  • Увеличение скорости (по сравнению с использованием обычных процессов). Многопоточность основана на использовании облегченных процессов (lightweight processes), работающих в общем пространстве виртуальной памяти. Благодаря многопоточности, не возникает больше неэффективных ситуаций, типичных для классической системе UNIX, в которой каждая команда shell (даже команда вывода содержимого текущей директории ls исполнялась как отдельный процесс, причем в своем собственном адресном пространстве. В противоположность облегченным процессам, обычные процессы (имеющие собственное адресное пространство) часть называют тяжеловесными (heavyweight).
  • Использование общих ресурсов. Потоки одного процесса используют общую память и файлы.
  • Экономия. Благодаря многопоточности, достигается значительная экономия памяти, по причинам, объясненным выше. Также достигается и экономия времени, так как переключение контекста на облегченный процесс, для которого требуется только сменить стек и восстановить значения регистров, значительно быстрее, чем на обычный процесс (см. «Методы взаимодействия процессов «).

Использование мультипроцессорных архитектур. Это особенно важно в настоящее время, в период широкого использования многоядерных гибридных и многопроцессорных систем. Именно многопоточность программ, основанная на многоядерности процессора, дает возможность, наконец, почувствовать реальные преимущества параллельного выполнения. История многопоточности Как небезынтересно отметить, один из первых шагов на пути к широкому использованию многопоточности, по-видимому, был сделан в 1970-е годы советскими разработчиками компьютерной аппаратуры и программистами. МВК «Эльбрус-1», разработанный в 1979 году, поддерживал в аппаратуре и операционной системе эффективную концепцию процесса, которая была близка к современному понятию облегченного процесса. В частности, процесс в «Эльбрусе» однозначно характеризовался своим стеком. Иначе говоря, все процессы были облегченными и исполнялись в общем пространстве виртуальной памяти – других процессов в «Эльбрусе» просто не было! Концепция многопоточности начала складываться, по-видимому, с 1980-х гг. в системе UNIX и ее диалектах. Наиболее развита многопоточность была в диалекте UNIX фирмы AT

Читайте также:
Программа которая генерирует ключи
  • Mac C-threads – пользовательские потоки в системе MacOS;
  • Solaris threads – пользовательские потоки в ОС Solaris (рассмотрены позже в данной лекции).
  • Низкоуровневые потоки, в которые отображаются пользовательские потоки, называются потоками ядра (kernel threads). Они поддержаны и используются на уровне ядра операционной системы. Как и подходы к пользовательским потокам, подходы к архитектуре и реализации системных потоков и к отображению пользовательских потоков в системные в разных ОС различны .Например, собственные модели потоков ядра со своей спецификой реализованы в следующих ОС:

    • Windows 95/98/NT/2000/XP/2003/2008/7;
    • Solaris;
    • Tru64 UNIX;
    • BeOS;
    • Linux.

    Существуют различные модели многопоточности – способы отображения пользовательских потоков в потоки ядра. Теоретически возможны (и на практике реализованы) следующие модели многопоточности: — Модель много / один (many-to-one) – отображение нескольких пользовательских потоков в один и тот же поток ядра. Используется в операционных системах, не поддерживающих множественные системные потоки (например, с целью экономии памяти). Данная модель изображена на рис. 10.2. Рис. 10.2. Схема модели многопоточности «много / один». — Модель один / один (one-to-one) – взаимно-однозначное отображение каждого пользовательского потока в определенный поток ядра. Примеры ОС, использующих данную модель, — Windows 95/98/NT/2000/XP/2003/2008/7; OS/2. Данная модель изображена на рис. 10.3.

    Рис. 10.3. Схема модели многопоточности «один / один». — Модель много / много (many-to-many) – модель, допускающая отображение нескольких пользовательских потоков в несколько системных потоков. Такая модель позволяет ОС создавать большое число системных потоков. Характерным примером ОС, использующей подобную модель, является ОС Solaris, а также Windows NT / 2000 / XP / 2003 / 2008 / 7 с пакетом ThreadFiber. Данная модель изображена на рис. 10.4. Рис. 10.4. Схема модели многопоточности «много / много». Проблемы многопоточности Многопоточность – весьма сложная, еще не полностью изученная и, тем более, не полностью формализованная область, в которой имеется много интересных проблем. Рассмотрим некоторые из них. Семантика системных вызовов fork() и exec(). Как уже отмечалось, в классической ОС UNIX системный вызов fork создает новый «тяжеловесный» процесс со своим адресным пространством, что значительно «дороже», чем создание потока. Однако, с целью поддержания совместимости программ снизу вверх, приходится сохранять эту семантику, а многопоточность вводить с помощью новых системных вызовов. Прекращение потоков. Важной проблемой является проблема прекращения потоков: например, если родительский поток прекращается, то должен ли при этом прекращаться дочерний поток? Если прекращается стандартный процесс, создавший несколько потоков, то должны ли прекращаться все его потоки? Ответы на эти вопросы в разных ОС неоднозначны. Обработка сигналов. Сигналы в UNIX – низкоуровневый механизм обработки ошибочных ситуаций. Примеры сигналов: SIGSEGV — нарушение сегментации (обращение по неверному адресу, чаще всего по нулевому); SIGKILL – сигнал процессу о выполнении команды kill его уничтожения. Пользователь может определить свою процедуру-обработчик сигнала системным вызовом signal. Проблема в следующем: как распространяются сигналы в многопоточных программах и каким потоком они должны обрабатываться? В большинстве случаев этот вопрос решается следующим образом: сигнал обрабатывается потоком, в котором он сгенерирован, и влияет на исполнение только этого потока. В более современных ОС (например, Windows 2000 и более поздних версиях Windows), основанных на объектно-ориентированной методологии, концепция сигнала заменена более высокоуровневой концепцией исключения (exception). Исключение распространяется по стеку потока в порядке, обратном порядку вызовов методов, и обрабатывается первым из них, в котором система находит подходящий обработчик. Аналогичная схема обработки исключений реализована в Java и в .NET. Группы потоков. В сложных задачах, например, задачах моделирования, при числе разнородных потоков, возникает потребность в их структурировании и помощью концепции группы потоков – совокупности потоков, имеющей свое собственное имя, над потоками которой определены групповые операции. Наиболее удачно, с нашей точки зрения, группы потоков реализованы в Java (с помощью класса ThreadGroup). Следует отметить также эффективную реализацию пулов потоков (ThreadPool) в .NET. Локальные данные потока (thread-local storage — TLS) – данные, принадлежащие только определенному потоку и используемые только этим потоком. Необходимость в таких данных очевидна, так как многопоточность – весьма важный метод распараллеливания решения большой задачи, при котором каждый поток работает над решением порученной ему части. Все современные операционные системы и платформы разработки программ поддерживают концепцию локальных данных потока. Синхронизация потоков. Поскольку потоки, как и процессы (см. «Методы взаимодействия процессов «) могут использовать общие ресурсы и реагировать на общие события, необходимы средства их синхронизации. Эти средства подробно рассмотрены позже в данном курсе. Тупики (deadlocks) и их предотвращение. Как и процессы (см. «Методы взаимодействия процессов «), потоки могут взаимно блокировать друг друга (т.е. может создаться ситуация deadlock), при их неаккуратном программировании. Меры по борьбе с тупиками подробно рассмотрены позже в данном курсе. Потоки POSIX (Pthreads) В качестве конкретной модели многопоточности рассмотрим потоки POSIX (напомним, что данная аббревиатура расшифровывается как Portable Operating Systems Interface of uniX kind – стандарты для переносимых ОС типа UNIX). Многопоточность в POSIX специфицирована стандартом IEEE 1003.1c, который описывает API для создания и синхронизации потоков. Отметим, что POSIX-стандарт API определяет лишь требуемое поведение библиотеки потоков. Реализация потоков оставляется на усмотрение авторов конкретной POSIX-совместимой библиотеки. POSIX-потоки распространены в ОС типа UNIX, а также поддержаны, с целью совместимости программ, во многих других ОС, например, Solaris и Windows NT. Стандарт POSIX определяет два основных типа данных для потоков: pthread_t – дескриптор потока; pthread_attr_t – набор атрибутов потока. Стандарт POSIX специфицирует следующий набор функций для управления потоками:

    • pthread_create(): создание потока
    • pthread_exit(): завершение потока (должна вызываться функцией потока при завершении)
    • pthread_cancel(): отмена потока
    • pthread_join(): заблокировать выполнение потока до прекращения другого потока, указанного в вызове функции
    • pthread_detach(): освободить ресурсы занимаемые потоком (если поток выполняется, то освобождение ресурсов произойдёт после его завершения)
    • pthread_attr_init(): инициализировать структуру атрибутов потока
    • pthread_attr_setdetachstate(): указать системе, что после завершения потока она может автоматически освободить ресурсы, занимаемые потоком
    • pthread_attr_destroy(): освободить память от структуры атрибутов потока (уничтожить дескриптор).

    Имеются следующие примитивы синхронизации POSIX-потоков с помощью мюьтексов (mutexes) – аналогов семафоров – и условных переменных (conditional variables) – оба эти типа объектов для синхронизации подробно рассмотрены позже в данном курсе:

    • — pthread_mutex_init() – создание мюьтекса;
    • — pthread_mutex_destroy() – уничтожение мьютекса;
    • — pthread_mutex_lock() – закрытие мьютекса;
    • — pthread_mutex_trylock() – пробное закрытие мьютекса (если он уже закрыт, вызов игнорируется, и поток не блокируется);
    • — pthread_mutex_unlock() – открытие мьютекса;
    • — pthread_cond_init() – создание условной переменной;
    • — pthread_cond_signal() – разблокировка условной переменной;
    • — pthread_cond_wait() – ожидание по условной переменной.

    Рассмотрим пример использования POSIX-потоков на языке Си. #include #include #include #include static void wait_thread(void) < time_t start_time = time(NULL); while (time(NULL) == start_time) < // никаких действий, кроме занятия процессора на время до 1 с. >> static void *thread_func(void *vptr_args) < int i; for (i = 0; i < 20; i++) < fputs(» bn», stderr); wait_thread(); >return NULL; > int main(void) < int i; pthread_t thread; if (pthread_create( return EXIT_FAILURE; >for (i = 0; i < 20; i++) < puts(«a»); wait_thread(); >if (pthread_join(thread, NULL) != 0) < return EXIT_FAILURE; >return EXIT_SUCCESS; > Пример иллюстрирует параллельное выполнение основного потока, выдающего в стандартный вывод последовательность букв «a», и дочернего потока, выдающего в стандартный поток ошибок (stderr) последовательность букв «b». Обратите внимание на особенности создания потока (pthread_create), указания его тела (исполняемой процедуры потока thread_func) и ожидания завершения дочернего потока (pthread_join). Потоки и процессы в Solaris В ОС Solaris, как уже было отмечено, используется модель потоков много / много. Кроме того, в системе используется также уже известное нам понятие облегченный процесс (lightweight process промежуточное между концепцией пользовательского потока и системного потока. Таким образом, в ОС Solaris каждый пользовательский поток отображается в свой облегченный процесс, который, в свою очередь, отображается в поток ядра; последний может исполняться на любом процессоре (или ядре процессора) компьютерной системы. Схема организации потоков в Solaris изображена на рис. 10.5. Рис. 10.5. Потоки в Solaris. На рис. 10.6 изображена схема организации процесса в ОС Solaris. Рис. 10.6. Процессы в Solaris. На схеме видно, что каждый процесс содержит, кроме стандартной информации блока управления процессом, также список всех своих облегченных процессов для управления ими.

    Источник: studfile.net

    Рейтинг
    ( Пока оценок нет )
    Загрузка ...
    EFT-Soft.ru