Как мне реализовать Wait/Die блокировки, которые позволяют избежать deadlock на ЯП С

Само задание я взял отсюда https://stepik.org/lesson/44341/step/14?unit=22147 Реализовать Wait/Die блокировки, которые позволяют избежать deadlock-ов.

Решать это задание можно только на языке C. Вам будут доступны блокировки (struct lock), переменные состояния (struct condition) и атомарные Read/Modify/Write регистры (atomic_int, atomic_uint, atomic_short, atomic_ushort, atomic_long, atomic_ulong, atomic_llong, atomic_ullong) с интерфейсом, который использовался в видео.

Проверяющая система будет оценивать вашу реализацию на ряде простых однопоточных тестов:

Если только один поток пытается захватить блокировку, то захват должен быть успешным

Попытка захвата одной блокировки несколько раз из одного потока не должна приводить к deadlock-у

Кроме простых однопоточных тестов, естественно, будет и многопоточный: несколько потоков будут пытаться захватить блокировки в таком порядке, который с большой вероятностью приведет к deadlock-у. Если ваше решение не укладывается в лимит времени, значит в вашем коде скорее всего случился deadlock.

Требуемый интерфейс реализации описан в шаблоне кода:

/* Напоминание, как выглядят интерфейсы блокировки и переменной
   состояния.
 
   ВАЖНО: обратите внимание на функции lock_init и condition_init,
          я не уделял этому внимание в видео, но блокировки и
          переменные состояния нужно инициализировать.
*/
 
struct lock;
void lock_init(struct lock *lock);
void lock(struct lock *lock);
void unlock(struct lock *lock);
 
struct condition;
void condition_init(struct condition *cv);
void wait(struct condition *cv, struct lock *lock);
void notify_one(struct condition *cv);
void notify_all(struct condition *cv);
 
 
 
/* Далее следует интерфейс, который вам нужно реализовать.
 
   ВАЖНО: в шаблоне кода структуры содержат поля, некоторые
          функции уже реализованы и присутствуют комментарии
          - это не более чем подсказка. Вы можете игнорировать
          комментарии, изменять поля структур и реализации
          функций на ваше усмотрение, при условии, что вы
          сохранили интерфейс.
 
          Вам нельзя изменять имена структур (wdlock_ctx и
          wdlock), а также имена функций (wdlock_ctx_init,
          wdlock_init, wdlock_lock, wdlock_unlock).
*/
 
struct wdlock_ctx;
 
struct wdlock {
    /* wdlock_ctx должен хранить информацию обо всех
       захваченных wdlock-ах, а это поле позволит связать
       wdlock-и в список. */
    struct wdlock *next;
 
    /* Текущий владелец блокировки - из него мы извлекаем
       timestamp связанный с блокировкой, если блокировка
       свободна, то хранит NULL. */
    const struct wdlock_ctx *owner;
 
    /* lock и cv могут быть использованы чтобы дождаться
       пока блокировка не освободится либо у нее не сменится
       владелец. */
    struct lock lock;
    struct condition cv;
};
 
 
/* Каждый контекст имеет свой уникальный timestamp и хранит
   список захваченных блокировок. */
struct wdlock_ctx {
    unsigned long long timestamp;
    struct wdlock *locks;
};
 
 
/* Всегда вызывается перед тем, как использовать контекст.
 
   ВАЖНО: функция является частью интерфейса - не меняйте
          ее имя и аргументы.
*/
void wdlock_ctx_init(struct wdlock_ctx *ctx)
{
    static atomic_ullong next;
 
    ctx->timestamp = atomic_fetch_add(&next, 1) + 1;
    ctx->locks = NULL;
}
 
/* Всегда вызывается перед тем, как использовать блокировку.
 
   ВАЖНО: функция является частью интерфейса - не меняйте
          ее имя и аргументы.
*/
void wdlock_init(struct wdlock *lock)
{
    lock_init(&lock->lock);
    condition_init(&lock->cv);
    lock->owner = NULL;
}
 
/* Функция для захвата блокировки l контекстом ctx. Если
   захват блокировки прошел успешно функция должна вернуть
   ненулевое значение. Если же захват блокировки провалился
   из-за проверки timestamp-а, то функция должна вернуть 0.
 
   Помните, что контекст должен хранить информацию о
   захваченных блокировках, чтобы иметь возможность освободить
   их в функции wdlock_unlock.
 
   ВАЖНО: функция является частью интерфейса - не меняйте
          ее имя и аргументы.
*/
int wdlock_lock(struct wdlock *l, struct wdlock_ctx *ctx)
{
    // Ваш код здесь
}
 
/* Функция для освобождения всех блокировок, захваченных
   контекстом ctx. При этом может случиться так, что этот
   контекст не владеет ни одной блокировкой, в этом случае
   ничего делать не нужно.
 
   ВАЖНО: функция является частью интерфейса - не меняйте
          ее имя и аргументы.
*/
 
void wdlock_unlock(struct wdlock_ctx *ctx)
{
    // Здесь я не знаю что написать 
}
   

Ответы (0 шт):