Информация об изменениях

Сообщение Re[5]: внутренняя реализация std::mutex? от 17.05.2018 6:15

Изменено 17.05.2018 6:19 lpd

Re[5]: внутренняя реализация std::mutex?
Здравствуйте, barney, Вы писали:

B>Т.е должен быть механизм, который отличает поток, ждущий futex от работающего потока, квант времени которого истек.

B>Иначе нет строгих гарантий что futex поток не проснется "внезапно" если планировщику вдруг так вздумается.
B>Т.е есть какой то системный condition variable в ядре, по которому поток "вешается" спать, до наступления сигнала ядра,
B>которое, например возникает когда другой поток освобождает тот же мьютекс?

Код mutex.lock() в user-level атомарно проверяет флаг занятости мьютекса, и, если он свободен, то просто захватывает его, и без вызова кода ядра возвращает управление захватывающему мьютекс коду. Если мьютекс уже кем-то занят, то mutex.lock() вызывает сисколл sys_futex(FUTEX_WAIT). Есть тонкость, что sys_futex в ядре еще раз проверяет занятость мьютекса на случай, если он освободился между проверкой mutex.lock() и sys_futex()(Это подробно описано в комментарии в коде ядра futex.c). Если фьютекс занят и поток нужно перевести в режим ожидания, то он добавляется в очередь, связанную в ядре с фьютексом.
Когда занимающий фьютекс поток освободит его вызовом mutex.unlock()(реализованный через сисколл sys_futex(FUTEX_WAKE)), код sys_futex(FUTEX_WAKE) в ядре выберет поток из очереди фьютекса и пометит его системному планировщику(у которого есть свой глобальный список потоков) для исполнения. Этот поток когда до него дойдет очередь получит квант времени, на него переключится контекст, он вернется из sys_futex(FUTEX_WAIT), и окажется в коде mutex.lock(). Код mutex.lock() на всякий случай проверит, не был ли снова занят mutex, и если успеет атомарно захватит его.
Re[5]: внутренняя реализация std::mutex?
Здравствуйте, barney, Вы писали:

B>Т.е должен быть механизм, который отличает поток, ждущий futex от работающего потока, квант времени которого истек.

B>Иначе нет строгих гарантий что futex поток не проснется "внезапно" если планировщику вдруг так вздумается.
B>Т.е есть какой то системный condition variable в ядре, по которому поток "вешается" спать, до наступления сигнала ядра,
B>которое, например возникает когда другой поток освобождает тот же мьютекс?

Да, у futex в ядре есть очередь ожидающих его потоков.
Код mutex.lock() в user-level атомарно проверяет флаг занятости мьютекса, и, если он свободен, то просто захватывает его, и без вызова кода ядра возвращает управление захватывающему мьютекс коду. Если мьютекс уже кем-то занят, то mutex.lock() вызывает сисколл sys_futex(FUTEX_WAIT). Есть тонкость, что sys_futex в ядре еще раз проверяет занятость мьютекса на случай, если он освободился между проверкой mutex.lock() и sys_futex()(Это подробно описано в комментарии в коде ядра futex.c). Если фьютекс занят и поток нужно перевести в режим ожидания, то он добавляется в очередь, связанную в ядре с фьютексом.
Когда занимающий фьютекс поток освободит его вызовом mutex.unlock()(реализованный через сисколл sys_futex(FUTEX_WAKE)), код sys_futex(FUTEX_WAKE) в ядре выберет ожидающий поток из очереди фьютекса и пометит его системному планировщику(у которого есть свой глобальный список потоков) для исполнения. Этот поток когда до него дойдет очередь получит квант времени, на него переключится контекст, он вернется из sys_futex(FUTEX_WAIT), и окажется в коде mutex.lock(). Код mutex.lock() на всякий случай проверит, не был ли снова занят mutex, и если успеет атомарно захватит его.