Как разделить ресурс между двумя группами потоков

Есть 2 группы потоков. В каждой группе по несколько потоков. Есть общий ресурс. Например какая - нибудь коллекция. Нужно, чтобы, когда хотя бы один поток из первой группы успел занять этот ресурс, все остальный из этой же группы могли к ней обращаться. И когда из первой группы перестали обращаться к ресурсу, то вторая будет имеет возможность ею владеть. Нужно, чтобы все это работало без каких - либо "менеджеров". Чисто, чтобы потоки как - то "договорились" между собой.


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

Автор решения: Serge3leo

Например, если упростить инициализацию, можно как-то так:

typedef int id_t;
typedef struct glock_t_ {
    pthread_mutex_t mtx;  // Синхронизация доступа к структуре
    id_t owner;  // В случае owner_cnt > 0 - id владеющей группы
    size_t owner_cnt;  // Число текущих владельцев блокировки
    pthread_cond_t wait;  // Очередь ожидания блокировки
    size_t wait_cnt;  // Длина очереди ожидания
} glock_t;
#define GLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, -1, 0, \
                            PTHREAD_COND_INITIALIZER, 0 }
void glock_lock(glock_t *lck, id_t id) {
    pthread_mutex_lock(&lck->mtx);
    lck->wait_cnt++;
    while (id != lck->owner && 0 < lck->owner_cnt) {
        pthread_cond_wait(&lck->wait, &lck->mtx);
    }
    lck->wait_cnt--;
    lck->owner = id;
    lck->owner_cnt++;
    pthread_mutex_unlock(&lck->mtx);
}
void glock_unlock(glock_t *lck) {
    pthread_mutex_lock(&lck->mtx);
    assert(0 < lck->owner_cnt);
    lck->owner_cnt--;
    if (0 == lck->owner_cnt && 0 < lck->wait_cnt) {
        pthread_cond_broadcast(&lck->wait);
    }
    pthread_mutex_unlock(&lck->mtx);
}

P.S.

В принципе, корректно обрабатывается любое число групп (различных id). Но для числа групп большего 2, с точки зрения эффективности, желательна переработка очереди ожидания.

Так же, можно обеспечить лучший "быстрый путь" и, при необходимости, решение проблемы "инверсии приоритета".

→ Ссылка