%3F.png)
О вышеизложенномсвязьчто подразумевается под этим parent_tidptr
и child_tidptr
на основании do_fork()
чего создается новый процесс?
решение1
Давайте начнем с рассмотрения интерфейса системных вызовов. Он немного различается в зависимости от архитектуры, но на x86-64 он выглядит так:
long clone(unsigned long flags, void *child_stack,
int *ptid, int *ctid,
unsigned long newtls);
ptid
и ctid
ваши parent_tidptr
и child_tidptr
. Теперь давайте посмотрим, чтоclone(2)
на странице руководства написано:
CLONE_CHILD_CLEARTID (since Linux 2.5.49)
Erase the child thread ID at the location ctid in
child memory when the child exits, and do a wakeup on
the futex at that address.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the
child's memory.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the
parent's memory.
Эти флаги были изначально разработаны для реализации потоковых библиотек. Если мы посмотрим на реализацию NPTLpthread_create()
внутри glibc мы в конечном итоге находим код вsysdeps/unix/sysv/linux/createthread.c
который делает clone()
вызов, включающий CLONE_PARENT_SETTID
и CLONE_CHILD_CLEARTID
в flags
.
В этом clone()
вызове мы также можем видеть, что аргументы ptid
иctid
указывают на тот же адрес. (Помните, что потоки POSIX совместно используют адресное пространство; это достигается с помощью флага clone()
CLONE_VM
.)
Итак, здесь происходит следующее.
CLONE_PARENT_SETTID
используется для обеспечения того, чтобы идентификатор потока ядра сохранялся в определенном месте в пространстве пользователя. Сторона пользовательского пространства реализации потоков должна знать этот идентификатор потока.CLONE_CHILD_CLEARTID
используется для очистки (т. е. обнуления) того же места приclone()
завершении потока, созданного .
Давайте пойдем немного дальше...
Идентификатор потока, возвращаемый через ptid
/, ctid
равеннетто же самое, что и идентификатор потока POSIX ( pthread_t
), хотя в реализациях потоков 1:1, таких как NPTL, существует однозначное соответствие между идентификаторами потоков ядра и идентификаторами потоков POSIX. Идентификатор потока ядра — это тот же идентификатор, который вы получаете, используя Linuxgettid()
call. Он также возвращается clone()
как возвращаемое значение системного вызова, что наводит на вопрос: зачем нам нужен ptid
/ ctid
? Проблема в том, что со стороны пользовательского пространства все выглядит так:
tid = clone(...);
С точки зрения реализации потоков в пользовательском пространстве здесь имеет место гонка, поскольку присваивание tid
происходит толькопосле clone()
возвращает. Это означает, что потоковая библиотека пользовательского пространства может столкнуться с определенными проблемами, если она захочет получить эту информацию до того, как новый поток что-либо сделает (например, завершит). Использование CLONE_PARENT_SETTID
гарантирует, что новый идентификатор потока будет помещен в место, на которое указываетptid
до
clone()
возвращает и, таким образом, позволяет потоковой библиотеке избегать подобных состояний гонки. ( CLONE_CHILD_SETTID
может также использоваться для аналогичного эффекта.)
Причина, по которой CLONE_CHILD_CLEARTID
используется очистка ptid
/, ctid
заключается в том, чтобы предоставить путь дляpthread_join()
позвоните в другой поток, чтобы обнаружить, что поток завершился. По сути, местоположение ptid
/ ctid
используется какфутекс, иfutex()
системный вызов используется для блокировки, ожидая изменения целого числа в этом месте. (Детали немного запутаны, но grep
для использования lll_wait_tid
и lll_futex_wait
в исходном коде glibc. В конечном счете, происходит FUTEX_WAIT
операция. Вспомните выше, что CLONE_CHILD_CLEARTID
делает пробуждение фьютекса по целевому адресу.)
решение2
tid
означает "thread id". Параметры parent_tidptr
и child_tidptr
указывают на память пользовательского пространства в адресном пространстве родительского процесса и адресном пространстве дочернего процесса соответственно. Идентификатор вновь созданного потока хранится в переменных int, на которые указывают указатели.
Для получения более подробной информации см.clone(2)
страница руководства.