Потоки и управление ими

Содержание

Слайд 2

Потоки и управление ими

Первый аргумент этой функции thread - это указатель на

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

Слайд 3

Потоки и управление ими

Единственное что сказано в стандарте, это что эти значения

Потоки и управление ими Единственное что сказано в стандарте, это что эти
можно копировать, и что используя вызов int pthread_equal(pthread_t thr1, pthread_t thr2) мы можем установить что оба идентификатора thr1 и thr2 идентифицируют один и тот же поток (при этом они вполне могут быть неравны в смысле оператора равенства). Подобными свойствами обладает большинство типов используемых в данном стандарте!

Слайд 4

Потоки и управление ими

Второй аргумент этой функции attr - указатель на переменную

Потоки и управление ими Второй аргумент этой функции attr - указатель на
типа pthread_attr_t, которая задает набор свойств создаваемой нити. Здесь мы сталкиваемся со второй особенностью POSIX API, а именно с концепцией атрибутов. Дело в том, что в этом API во всех случаях, когда при создании или инициализации некоторого объекта необходимо задать набор неких дополнительных его свойств, вместо указания этого набора при помощи набора параметров вызова используется передача предварительно сконструированного объекта, представляющего этот набор атрибутов.

Слайд 5

Потоки и управление ими

Такое решение имеет, по крайней мере, два преимущества. Во-первых,

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

Слайд 6

Потоки и управление ими

Третий аргумент вызова pthread_create - это указатель на функцию

Потоки и управление ими Третий аргумент вызова pthread_create - это указатель на
типа void* ()(void *). Именно эту функцию и начинает выполнять вновь созданный поток, при этом в качестве параметра этой функции передается четвертый аргумент вызова pthread_create. Таким образом можно с одной стороны параметризовать создаваемый поток кодом, который он будет выполнять, с другой стороны параметризовать его различными данными передаваемыми коду.

Слайд 7

Потоки и управление ими

Функция pthread_create возвращает нулевое значение в случае успеха и

Потоки и управление ими Функция pthread_create возвращает нулевое значение в случае успеха
ненулевой код ошибки в случае неудачи. Это также одна из особенностей POSIX API, вместо стандартного для Unix подхода, когда функция возвращает лишь некоторый индикатор ошибки, а код ошибки устанавливает в переменной errno. Функции POSIX API возвращают код ошибки в результате своего аргумента.

Слайд 8

Потоки и управление ими

Очевидно, это связано с тем, что с появлением в

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

Слайд 9

Потоки и управление ими

В качестве резюме рассмотрим пример.
Заметим, что хотя функции работы

Потоки и управление ими В качестве резюме рассмотрим пример. Заметим, что хотя
с потоками описаны в файле включения pthread.h, на самом деле они находятся в библиотеке. Поэтому процесс компиляции и сборки многопоточной программы выполняется в два этапа:
gcc -Wall -c -o test.o test.c
gcc -Wall -o test test.o libgcc.a -lpthread
В большинстве версий Linux библиотека лежит в /usr/lib/.

Слайд 10

Завершение потока

Поток завершается, когда происходит возврат из функции. Если мы хотим

Завершение потока Поток завершается, когда происходит возврат из функции. Если мы хотим
получить возвращаемое этой функцией значение, то мы должны воспользоваться такой функцией:
int pthread_join(pthread_t thread, void** value_ptr)
Эта функция дожидается завершения потока с идентификатором thread, и записывает возвращае-мое ею значение в переменную, на которую указывает value_ptr. При этом освобождаются все ресурсы связанные с потоком, потому эта функция может быть вызвана для данного потока только один раз.

Слайд 11

Завершение потока

Если нас чем-то не устраивает возврат значения через pthread_join, например,

Завершение потока Если нас чем-то не устраивает возврат значения через pthread_join, например,
необходимо получить данные из нескольких потоков, то следует воспользоваться каким либо другим механизмом, например, организовать очередь возвращаемых значений, или возвращать значение в структуре, указатель на которую передают в качестве параметра потока. То есть использование pthread_join - это вопрос удобства, а не догма, в отличие от случая пары fork() - wait().

Слайд 12

Завершение потока

В случае, если мы хотим использовать другой механизм возврата или

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

Слайд 13

Завершение потока

Во-вторых, любой поток можно отсоединить, вызвав в любой момент его

Завершение потока Во-вторых, любой поток можно отсоединить, вызвав в любой момент его
жизни (то есть до вызова pthread_join()) функцию int pthread_detach(pthread_t thread), и указав ей в качестве параметра идентификатор потока. При этом поток вполне может отсоединить сам себя, получив свой идентификатор при помощи функции pthread_t pthread_self(void). Следует подчеркнуть, что отсоединение потока никоим образом не влияет на процесс его выполнения, а просто помечает поток как готовый по своему завершению к освобождению ресурсов.

Слайд 14

Завершение потока

Под освобождаемыми ресурсами подразумеваются в первую очередь стек, память, в

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

Слайд 15

Завершение потока

Помимо возврата из функции потока существует вызов, аналогичный вызову exit()

Завершение потока Помимо возврата из функции потока существует вызов, аналогичный вызову exit()
для процессов:
int pthread_exit(void *value_ptr)
Этот вызов завершает выполняемый поток, возвращая в качестве результата его выполнения value_ptr. Реально при вызове этой функции поток из нее просто не возвращается. Помните, что функция exit() по-прежнему завершает процесс, то есть в том числе уничтожает все потоки.

Слайд 16

Завершение потока

Рассмотрим соответствующий пример.
Заметим, что способ обработки запроса на прерывание потока

Завершение потока Рассмотрим соответствующий пример. Заметим, что способ обработки запроса на прерывание
зависит от состояния указанного потока. Две функции, pthread_setcancelstate() и pthread_setcanceltype(), определяют это состояние.

Слайд 17

Особенности главного потока

Как известно, программа на Си начинается с выполнения функции

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

Слайд 18

Особенности главного потока

Возврат из этого потока завершает весь процесс, что бывает иногда

Особенности главного потока Возврат из этого потока завершает весь процесс, что бывает
удобно, так как не надо явно заботиться о завершении остальных потоков. Если мы не хотим, чтобы по завершении этого потока остальные потоки были уничтожены, то следует воспользоваться функцией pthread_exit.
У функции этого потока не один параметр типа void*, как у остальных, а пара argc-argv. Строго говоря функция main не является функцией потока, так как в большинстве ОС она сама вызывается некими функциями, которые подготавливают ее выполнение.

Слайд 19

Особенности главного потока

В-третьих, многие реализации отводят на стек начального потока гораздо

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

Слайд 20

Жизненный цикл потока

Рассмотрим жизненный цикл потока, а именно последовательность состояний, в

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

Слайд 21

Жизненный цикл потока

Жизненный цикл потока

Слайд 22

Жизненный цикл потока

Жизненный цикл потока

Слайд 23

Жизненный цикл потока

Жизненный цикл потока

Слайд 24

Жизненный цикл потока

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

Жизненный цикл потока Потоки могут создаваться системой, например, начальный поток, который создается
создании процесса, или при помощи явных вызовов pthread_create() пользовательским процессом. Однако любой создаваемый поток начинает свою жизнь в состоянии "готов". После чего в зависимости от политики планирования системы он может либо сразу перейти в состояние "выполняется", либо перейти в него через некоторое время.
Имя файла: Потоки-и-управление-ими.pptx
Количество просмотров: 33
Количество скачиваний: 0