pthread_rwlock_rdlock(&loc);
for (list
if (*i == e) {
delay(READ_DELAY);
break;
}
pthread_rwlock_unlock(&loc);
if (n == size) n = -1;
return n;
}
} data;
А теперь пришло время сравнить варианты:
# nice -n-19 sy10 500 .2
evaluation time: 1.2296 sec.
# nice -n-19 sy11 500 .2
evaluation time: 1.24973 sec.
# nice -n-19 sy12 500 .2
evaluation time: 0.440904 sec.
При «жесткой» блокировке мы не получаем никакого выигрыша за счет параллельного выполнения запросов к данным, а при использовании блокировки чтения/записи — 3-кратный выигрыш. Проделаем то же самое, но в условиях гораздо меньшей интенсивности обновления данных относительно общего потока запросов:
# nice -n-19 sy10 500 .02
evaluation time 0.989699 sec.
# nice -n-19 sy11 500 .02
evaluation time 0.98391 sec.
# nice -n-19 sy12 500 .02
evaluation time 0.0863443 sec.
Выигрыш становится более чем 10-кратным.
Показанные примеры (
delay
) на активные процессорные операции над данными, но общие тенденции сохраняются.
Спинлок, или «крутящаяся» блокировка, предназначен исключительно для применения в системах SMP (Symmetrical Multi-Processing), то есть в многопроцессорных системах. Поведение спинлока практически идентично классическому мьютексу, за единственным исключением — ожидающий поток не блокируется и не вытесняется. Не забывайте, речь идет о многопроцессорной системе! Основным назначением спинлока является задержка выполнения обработчиков прерываний, и предназначены они для исключения временных потерь, связанных с переключением контекстов.
Функции работы с «крутящейся» блокировкой объявлены в заголовочном файле
<рthread.h>
. Самих функций немного, и они имеют минимальные возможности по настройке. Спинлок не поддерживает тайм-ауты. Появление этого элемента синхронизации в QNX Neutrino связано с требованиями стандарта POSIX 1003.1j (draft).
int pthread_spin_init(pthread_spinlock_t* spinner, int pshared);
Функция инициализирует объект синхронизации спинлока блокировки, на который указывает аргумент
spinner
, и устанавливает для него параметр доступа из других процессов в соответствии со значением переменной
pshared
. Эта переменная может принимать следующие значения:
•
PTHREAD_PROCESS_SHARED
— с объектом спинлок может оперировать поток любого процесса, имеющего доступ к памяти, в которой распределен объект спинлок;
•
PTHREAD_PROCESS_PRIVATE
— доступ к объекту синхронизации возможен только для потоков процесса, из адресного пространства которого была распределена память объекта синхронизации.
В случае успешного завершения функция возвращает нулевое значение, в противном случае — один из следующих кодов ошибок:
AGAIN
— системе не хватает ресурсов для инициализации блокировки;
EBUSY
— объект крутящейся блокировки, на который указывает
spinner
, уже инициирован;
EINVAL
— некорректный объект
spinner
;
ENOMEM
— система не имеет достаточного количества свободной памяти для создания нового объекта.
int pthread_spin_destroy(pthread_spinlock_t* spinner);
Функция деинициализирует объект крутящейся блокировки. После деинициализации для последующего применения объекта он должен быть вновь инициализирован. Обратите внимание, результат функции не определен, если поток в данный момент крутится на блокировке, на которую указывает
spinner
, либо если объект
spinner
не был инициализирован.
Возвращаемые значения:
EOK
— успешное выполнение;
EBUSY
— блокировка используется другим потоком и не может быть разрушена;
EINVAL
— некорректный объект
spinner
.
int pthread_spin_lock(pthread_spinlock_t* spinner);
int pthread_spin_trylock(pthread_spinlock_t* spinner);