Допустим, у нас есть процесс, состоящий из четырех потоков. В операционных системах с явной поддержкой потоков должен существовать дескриптор процесса, который далее указывает на четыре потока. Дескриптор процесса описывает совместно используемые ресурсы, такие как адресное пространство и открытые файлы. Потоки описываются ресурсами, которые принадлежат только им. В ОС Linux, наоборот, существует просто четыре процесса и, соответственно, четыре обычные структуры task_struct
. Четыре процесса построены так, чтобы совместно использовать определенные ресурсы.
Потоки создаются так же, как и обычные задания, за исключением того, что в системный вызов clone()
передаются флаги с указанием, какие ресурсы должны использоваться совместно:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
Результат выполнения показанного кода будет таким же, как и при выполнении обычного вызова fork()
, за исключением того, что адресное пространство, ресурсы файловой системы, дескрипторы файлов и обработчики сигналов останутся общими. Другими словами, новая задача, так же как и родительский процесс, — обычные потоки. В отличие от этого, обычный вызов fork()
может быть реализован следующим образом:
clone(SIGCHLD, 0);
а вызов vfork()
в таком виде:
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);
Флаги, которые передаются в системный вызов clone()
, помогают указать особенности поведения нового процесса и детализировать, какие ресурсы должны быть общими для родительского и порожденного процессов. В табл. 3.1 приведены флаги системного вызова clone()
и их эффект.
Таблица 3.1. Флаги системного вызова clone()
Флаг | Описание |
---|---|
CLONE_FILES | Родительский и порожденный процессы совместно используют открытые файлы |
CLONE_FS | Родительский и порожденный процессы совместно используют информацию о файловой системе |
CLONE_IDLETASK | Установить значение PID в нуль (используется только для холостых (idle) задач) |
CLONE_NEWNS | Создать новое пространство имен для порожденной задачи |
CLONE_PARENT | Родительский процесс вызывающего процесса становится родительским и для порожденного |
CLONE_PTRACE | Продолжить трассировку и для порожденного процесса |
CLONE_SETTID | Возвратить значение идентификатора TID в пространство пользователя |
CLONE_SETTLS | Для порожденного процесса создать новую область локальных данных потока (thread local storage, TLS) |
CLONE_SIGHAND | У порожденного и родительского процессов будут общие обработчики сигналов |
CLONE_SYSVSEM | У родительского и порожденного процессов будет общая семантика обработки флага SEM_UNDO для семафоров System V |
CLONE_THREAD | Родительский и порожденный процессы будут принадлежать одной группе потоков |
CLONE_VFORK | Использовать vfork() : родительский процесс будет находиться а приостановленном состоянии, пока порожденный процесс не возобновит его работу |
CLONE_UNTRACED | Запретить родительскому процессу использование флага CLONE_PTRACE для порожденного процесса |
CLONE_STOP | Запустить процесс в состоянии TASK_STOPPED |
CLONE_CHILD_CLEARTID | Очистить идентификатор TID для порожденного процесса |
CLONE_CHILD_SETTID | Установить идентификатор TID для порожденного процесса |
CLONE_PARENT_SETTID | Установить идентификатор TID для родительского процесса |
CLONE_VM | У порожденного и родительского процессов будет общее адресное пространство |
Потоки в пространстве ядра