Реализация блокировки с использованием теста и набора
Ниже приведен код, приведенный в книге OSTEP, касающейся реализации блокировки с использованием инструкций test и set. Мой вопрос заключается в том, что в такой реализации поток, не удерживающий блокировку, не может вызвать функцию разблокировки и снять блокировку?
typedef struct __lock_t {
int flag;
} lock_t;
void init(lock_t *lock) {
// 0 indicates that lock is available, 1 that it is held
lock->flag = 0;
}
void lock(lock_t *lock) {
while (TestAndSet(&lock->flag, 1) == 1)
; // spin-wait (do nothing)
}
void unlock(lock_t *lock) {
lock->flag = 0;
}
2 ответа
Предполагается, что это ошибка кодирования, поэтому такого случая быть не должно.
Мой вопрос в том, что в такой реализации не может ли поток, который не удерживает блокировку, вызвать функцию разблокировки и снять блокировку?
Нет ничего плохого в том, например, что один поток получает блокировку, уведомляет другой поток о том, что он может продолжать работу (или, возможно, порождает новый поток), а затем другой поток освобождает блокировку.
Что-то очень неправильно, если один поток получает блокировку, а затем освобождает ее дважды.
Чтобы обнаруживать ошибки (при этом поддерживая все допустимые сценарии), вы хотите обнаружить «вызывается, когда блокировка не удерживается». Вы можете сделать это, используя атомный
TestAndClear()
в
unlock()
.
Если вы хотите применить «только поток, который получил блокировку, может освободить блокировку», тогда вам нужно знать, какой поток получил блокировку, поэтому вам нужно сохранить идентификатор потока в блокировке, когда он получен (например, с помощью атомарного «сравнить и обменять, если было равно»).