Получите блокировку чтения / записи, если она еще не удержана - PullRequest
0 голосов
/ 17 марта 2019

В GLib есть ли операция, чтобы сказать ей «получить блокировку, если вы ее еще не удерживали»?Может ли один и тот же поток получить блокировку дважды (сделать второе получение бездействующим или требовать, чтобы он был освобожден дважды) или проверить, удерживает ли он уже конкретную блокировку?

Предположим, у меня есть следующие функции вмой код:

void func_a() {
    //g_rw_lock_writer_lock(&shared_data->rw_lock);
    mess_with_data(shared_data);
    func_b();
    //g_rw_lock_writer_unlock(&shared_data->rw_lock);
}

void func_b() {
    //g_rw_lock_writer_lock(&shared_data->rw_lock);
    mess_with_data_again(shared_data);
    //g_rw_lock_writer_unlock(&shared_data->rw_lock);
}

Предположим, что:

  • shared_data указывает на общую структуру данных, и доступ должен быть синхронизирован между потоками
  • shared_data->rw_lock блокировка чтения / записи для синхронизации доступа
  • И func_a(), и func_b() можно вызывать извне
  • mess_with_data() и mess_with_data_again() не являются поточно-ориентированными, поэтомувызывающая сторона должна удерживать блокировку записи данных перед их вызовом
  • Это не просто отдельные вызовы функций, а строки операторов, поэтому копирование тела func_b() в func_a() не вариант (дублирование кода, плохая ремонтопригодность)
  • Вызывающие абоненты func_a() и func_b() не имеют прямого доступа к замку, поэтому блокировка должна происходить под капотом
  • Извлечение тела функции из func_b()(без локking / unlocking) в отдельную вспомогательную функцию, вызываемую как func_a(), так и func_(), не является опцией (они распределены по нескольким модулям, и между вызовами функций существуют уровни абстракции - на самом деле, func_a() не делаетнапрямую позвоните func_b() по имени, но указатель, который может разрешить func_b()).

Как мне решить эту проблему?

1 Ответ

1 голос
/ 17 марта 2019

Перво-наперво: слово, которое вы ищете, это " recursive ".

Хотя GMutex явно упоминает, что рекурсивный мьютекс не определен, AFAIK GRWLock просто не упоминает, является ли блокировка writer рекурсивной (сторона считывателя рекурсивной).

Если немного погрузиться в реализацию, вы увидите, что в POSIX GRWLock реализован с использованием pthread_rwlock_t, , который не должен быть рекурсивным («Результаты не определены, если вызывающий поток удерживает блокировку чтения-записи (будь то блокировку чтения или записи) во время вызова. "). Так что в принципе нет, GRWLock не является рекурсивным для блокировок писателя.

Что касается решения вашей проблемы, мое первое предложение было бы сделать так, чтобы mess_with_data и mess_with_data_again сами получили и сняли блокировку. Помните, что вы должны удерживать замки только столько, сколько необходимо и больше.

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

Также возможно реорганизовать mess_with_data и mess_with_data_again, чтобы они не требовали блокировок, но это может быть или не быть возможным и, вероятно, будет довольно трудным.

...