Реализация блокировки с использованием теста и набора

Ниже приведен код, приведенный в книге 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().

Если вы хотите применить «только поток, который получил блокировку, может освободить блокировку», тогда вам нужно знать, какой поток получил блокировку, поэтому вам нужно сохранить идентификатор потока в блокировке, когда он получен (например, с помощью атомарного «сравнить и обменять, если было равно»).

Другие вопросы по тегам