Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Дело в том, что внутри ядра мьютекс реализован с помощью спинлоков, а вот спинлоки реализованы сами по себе, автономно. Они — действительно базовый примитив. Ниже — только сам процессор.
Часто под mutex'ом понимают примитив, имеющим дополнительную семантику, связанную с переключением контекста при невозможности его захвата
Верно ли это? По мне, если говорить не академическим языком, мьютекс — черный ящик, который может быть в каждый момент времени захвачен только одним потоком. Спинлок ли это в чистом виде, комбинация спинлока и засыпания или попытка захвата и засыпание — детали реализации.
У того же Таненбаума спинлок, семафор и мьютекс (который рассматривается как частный случай семаформа с максимальным значением 1) разделены
Теперь рассмотрим некоторые примитивы взаимодействия процессов, которые блокируют работу, пока им не разрешается входить в критическую область, вместо напрасной траты времени центрального процессора.Далее описаны примитивы sleep/wakeup. Ещё дальше, в 2.3.5-2.3.6 описаны семафоры и мьютексы. А после — мониторы. При чтении у меня складывается впечатление, что все описанные вещи — примитивы синхронизации, но в разных системах и на разных уровнях примитивами являются те или иные объекты, над которыми уже достраивается остальное.
In NPTL, thread synchronization primitives (mutexes, thread joining, and so on) are implemented using the Linux futex(2) system call.
Раздел 2.3, где описаны спинлоки, называется «Взаимодействие процессов»… При чтении у меня складывается впечатление, что все описанные вещи — примитивы синхронизации, но в разных системах и на разных уровнях примитивами являются те или иные объекты, над которыми уже достраивается остальное
Почему вы называете мьютекс примитивом, если он прекрасно определяется через семафор?
They are(мьютексы)
easy and efficient to implement, which makes them especially useful in thread
packages that are implemented entirely in user space.
Because mutexes are so simple, they can easily be implemented in user space
proVided that a TSL or XCHG instruction is available. The code for mutex lock and
mutex_unlock for use with a user-level threads package are shown in Fig. 2-29.
The solution with XCHG is essentially the same.
mutex_lock:
TSL REGISTER,MUTEX
CMP REGISTER,#O
JZE ok
CALL thread_yield
JMP mutex_lock
ok: RET
mulex_unlock:
MOVE MUTEX,#O
RET
Figure 2·29. Implementation of mutex_lock and mutex_unlockВот тебе и «мьютекс или спинлок» и «каноничная реализация мьютекса».Это чистая реализация мьютекса, вызов thread_yield кагбэ намекаэ. А то, что она более эффективна, чем спинлок, так это в контексте идеального userspace'а.
int pthread_mutex_lock(pthread_mutex_t *mutex) {
if (mutex->kind == PTHREAD_MUTEX_NORMAL){
if (atomic_exchange(&mutex->lock, 1) != 0) {
while (atomic_exchange(&mutex->lock, -1) != 0) {
if (waitone(mutex->event, INFINITE) != 0) return EINVAL;
}
}
} else {
pthread_t self = pthread_self();
if (atomic_exchange(&mutex->lock, 1) == 0) {
mutex->recursion = 1;
mutex->owner = self;
} else {
if (pthread_equal(mutex->owner, self)) {
if (mutex->kind == PTHREAD_MUTEX_RECURSIVE) {
mutex->recursion++;
} else {
return EDEADLK;
}
} else {
while (atomic_exchange(&mutex->lock, -1) != 0) {
if (waitone(mutex->event, INFINITE) != 0) return EINVAL;
mutex->recursion = 1;
mutex->owner = self;
}
}
}
}
return 0;
}Userspace здесь не имеет значения.
Первая инструкция — load linked — просто читает значение из памяти. Но при этом в процессоре взводится триггер, который «следит» за считанной ячейкой — не было ли в неё записи.
Вторая — store conditional — сохраняет значение в память. Но! Если со времени исполнения load linked в эту ячейку кто-то уже записал новое значение, store conditional вернёт признак неуспеха (и, конечно, ничего в ячейку памяти записывать не будет).
Ядро #0, а потом #3 попытались что-то записать. Будет ли хотя бы одна попытка записи успешной?
Когда сеанс общения с ячейкой считается законченным, и после нового LL можно будет перезаписать ячейку?
например, если LL и SC лежат в памяти слишком далеко
#1 выполнило SC (удачно)
#2 выполнило SC (неудачно)
#3, #4 выполнили LL (с той же ячейкой)
#0 выполнило SC (???)
#3 выполнило SC (???)#1 выполнило SC (удачно)
#2 выполнило SC (неудачно)
#3, #4 выполнили LL (с той же ячейкой)
#3 выполнило SC (???)
#0 выполнило SC (???)В смысле исполняемые инструкции?
Считается, что инициирована новая последовательность?
The TCI66xx and C66xx devices do not support automated cache coherency because of the power consumption involved and the latency overhead introduced. Realtime applications targeted for these devices require predictability and determinism, which comes from data coherency being coordinated at select times by the application software. As developers manage this coherency, they develop designs that run faster and at lower power because they control when and if local data must be replicated into different memories.
Обзор примитивов синхронизации — спинлоки и тайны ядра процессора