Sign in Join
Wiki copytemporary

Threads/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Threads/ru

OldNewLine
1+Free Pascal поддерживает программирование потоков с процедурным и объектно-ориентированным интерфейсом, который в основном не зависит от платформы.
2+
3+Официальная документация находится здесь: [Programmer's guide chapter 10](https://www.freepascal.org/docs-html/prog/progch10.html). Оно подробно описывает интерфейс процедурных потоков.
4+
5+Объектно-ориентированный интерфейс `TThread` описан более полно на этой странице: [[Multithreaded Application Tutorial/ru|Руководство по разработке многопоточного приложения]]
6+
7+## Заметки по процедурному управлению потоками
8+
9+`BeginThread` возвращает дескриптор потока (handle) напрямую, а также возвращает идентификатор потока (ID) в качестве выходного параметра. В системах Posix дескрипторы потоков (handle) отсутствуют, поэтому копия идентификатора потока возвращается и как идентификатор (ID), и как дескриптор(handle). В Windows дескриптор потока (handle) используется для управления всеми потоками, а ID - это отдельное уникальное значение, используемое в качестве перечислителя потоков. Следовательно, независимо от платформы, дескриптор потока, возвращаемый `BeginThread`, соответствует ожиданиям всех других функций потоковой передачи RTL. (`CloseThread`, `SuspendThread`, `WaitForThreadTerminate` и т.д.)
10+
11+`GetCurrentThreadID` возвращает конкретно идентификатор потока (ID), а не дескриптор (handle). Таким образом, хотя вы можете использовать это в системах Posix для вызова функций потоковой передачи RTL, в Windows это не сработает. Чтобы получить дескриптор (handle), вы можете использовать `GetCurrentHandle` или `OpenThread` в Windows API или сохранить дескриптор (handle), полученный от `BeginThread`.
12+
13+Продолжительность жизни потока состоит из трех этапов:
14+
15+- Другой поток создает его, вызывая `BeginThread`.
16+- Поток завершает свою работу, затем выходит из функции верхнего уровня; или завершает себя явным образом, вызывая `EndThread`; или прибивается другим потоком при вызове `KillThread`.
17+- Другой поток обнаруживает, что поток завершен, и вызывает `CloseThread` для очистки.
18+
19+`CloseThread` ничего не делает в системах Posix, но в Windows освобождает дескриптор потока (handle). Если программа продолжает создавать новые потоки, но не закрывает их, это является утечкой ресурсов и в крайних случаях может привести к нестабильности системы. Все дескрипторы (handle) освобождаются, когда программа завершается, но по-прежнему рекомендуется явно вызывать `CloseThread`, как только поток завершится. Возвращаемое значение `CloseThread` всегда равно 0 в Posix и ненулевое в Windows в случае успеха.
20+
21+`DoneThread` и `InitThread` в системном модуле предназначены в первую очередь для внутреннего использования, игнорируйте их.
22+
23+`KillThread` следует избегать, если это вообще возможно. Если поток блокирует механизм ручной синхронизации при завершении, любой другой поток, ожидающий реализации этого механизма, может остаться в ожидании навсегда.
24+
25+`SuspendThread` и `ResumeThread` также опасны и даже не поддерживаются в системах Posix из-за аналогичных проблем с взаимоблокировкой. Кооперативная синхронизация - безопасная альтернатива (сами потоки периодически проверяют, получают ли они запрос на завершение работы).
26+
27+`ThreadGetPriority` и `ThreadSetPriority` позволяют устанавливать приоритет потока от -15 (простоя) до +15 (критический) в Windows. В Posix эти функции еще не реализованы через процедурный интерфейс.
28+
29+В модуле system есть функция [GetCPUCount](https://www.freepascal.org/docs-html/rtl/system/getcpucount.html). Используйте ее, чтобы оценить во время выполнения, сколько параллельных потоков нужно создать.
30+
31+## Синхронизация потоков
32+
33+Синхронизация используется для обеспечения безопасного доступа различных потоков или процессов к общим данным. Наиболее эффективные механизмы синхронизации предоставляются операционной системой; механизмы синхронизации FPC действуют как минимальная платформенно-нейтральная оболочка для механизмов операционной системы.
34+
35+Собственные механизмы синхронизации потоков в модуле system это: критические секции, события RTL, семафоры, `WaitForThreadTerminate`. Их код можно найти в **rtl/\<arch\>/cthreads.pp** или **rtl/\<arch\>/systhrd.inc**.
36+
37+Полностью межпроцессное взаимодействие требует более надежного решения, поскольку механизмов синхронизации потоков недостаточно. Для этого может подойти [SimpleIPC](https://www.freepascal.org/docs-html/fcl/simpleipc/index.html).
38+
39+### Критические секции
40+
41+Используются функции `InitCriticalSection`, `EnterCriticalSection`, `LeaveCriticalSection` и `DoneCriticalSection`.
42+
43+Критические секции - это совместный мьютекс кода, позволяющий только одному потоку одновременно входить в защищенный раздел кода при условии, что каждый поток входит и выходит из раздела чисто. Это безопасный кроссплатформенный способ защиты относительно небольших блоков кода.
44+
45+Потоки блокируются из секции только при вызове `EnterCriticalSection`. Если поток каким-то образом может попасть в раздел без вызова `EnterCriticalSection`, он не блокируется и раздел остается небезопасным. Потоки попадают в критическую секцию в порядке [FIFO](https://ru.wikipedia.org/wiki/FIFO).
46+
47+Мьютекс критической секции имеет счетчик блокировок. Если поток, содержащий мьютекс критической секции, вызывает `EnterCriticalSection` несколько раз, он должен вызвать `LeaveCriticalSection` равное количество раз, чтобы освободить мьютекс. Если поток выходит из раздела без вызова `LeaveCriticalSection`, например, из-за необработанного исключения, мьютекс остается заблокированным, а другие потоки, ожидающие его, также будут заблокированы.
48+
49+Вызов `LeaveCriticalSection`, когда мьютекс не заблокирован, вызывает ошибку в системах Posix, но в Windows он уменьшает счетчик блокировок до значения ниже 0. Вызов `DoneCriticalSection`, пока мьютекс все еще используется, вызывает ошибку в системах Posix, но в Windows он просто блокирует все потоки, ожидающие мьютекса, хотя любой поток, уже находящийся в критической секции, может нормально выйти.
50+
51+### RTLevent
52+
53+Функциями используются `RTLEventCreate`, `RTLEventSetEvent`, `RTLEventResetEvent`, `RTLEventWaitFor`, и `RTLEventDestroy`.
54+
55+События RTL являются предпочтительным методом межплатформенной синхронизации. События RTL запукаются как неустановленные. Они блокируют потоки, ожидающие их; когда событие установлено, один ожидающий поток освобождается (в порядке [FIFO](https://ru.wikipedia.org/wiki/FIFO)), и событие немедленно сбрасывается.
56+
57+Из-за различий в платформах невозможно напрямую запросить текущее состояние события. Также нет способа напрямую определить тайм-аут ожидания события, потому что любое ожидание события вызывает автоматический сброс состояния, а ожидания не имеют возвращаемого значения.
58+
59+Если поток начинает ждать события RTL, которое уже было установлено, ожидание завершается немедленно, и событие автоматически сбрасывается. Событие не учитывает, сколько раз оно было установлено, поэтому несколько наборов по-прежнему очищаются одним сбросом. Будьте осторожны: если у вас есть 8 потоков, которые начинают ждать одного события RTL, которое будет установлено 8 раз, потоки могут зайти в тупик, если что-то очистит несколько наборов за один сброс.
60+
61+Уничтожение события RTL, пока поток ожидает его, не освобождает поток. Ответственность за то, чтобы ни один поток не ожидал события после его уничтожения, лежит на программисте.
62+
63+### Семафоры
64+
65+Семафоры существовали только для Posix и устарели. Они блокируют ожидающие их потоки, и каждый `SemaphorePost` освобождает один ожидающий поток. Хотя семафоры недоступны через RTL, существуют и другие реализации. (где?)
66+
67+### WaitForThreadTerminate
68+
69+`WaitForThreadTerminate` блокирует текущий поток до тех пор, пока целевой поток не завершится. Параметр тайм-аута игнорируется на платформах Posix, и время ожидания никогда не истечет.
70+
71+Известно, что `WaitForSingleObject` и `WaitForMultipleObjects` не существуют в Linux, поэтому они не подходят для межплатформенного использования. Они могут быть полезны лишь под Windows.
72+
73+---
74+*From the Free Pascal wiki, page "Threads/ru", as it stood on 2020-08-21 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history