Как запустить bar () внутри foo (), если bar () и foo () являются взаимоисключающими - PullRequest
0 голосов
/ 21 мая 2019

У меня есть две функции, скажем, foo () и bar (), я хочу, чтобы они были взаимоисключающими, то есть полностью блокировали запуск foo (), когда работает bar (), или полностью блокировали запуск bar (), когда foo() выполняется для обеспечения безопасности потоков.

Однако я могу вызвать bar () внутри foo (), то есть когда foo () вызывает bar () внутри foo (), пусть bar () запускается,но никакие другие темы не вызывают bar ().

Возможно ли это?Если да, можете ли вы дать общую идею, пожалуйста?

Попытка использовать один или несколько мьютексов в C, легко сделать две функции взаимоисключающими, но тогда я не могу вызвать bar () внутри foo (),они войдут в тупик.

Я не могу просто разблокировать мьютекс прямо перед вызовом bar () внутри foo (), потому что я не могу гарантировать, что следующий запуск bar () будет вызван внутри foo ().

Я ищу решение, при котором foo блокирует bar, а bar блокирует foo, если они запускаются в разных потоках.но когда foo вызывает bar внутри своего тела (тот же поток), пусть bar запускается.

Спасибо

Ответы [ 2 ]

4 голосов
/ 21 мая 2019

Самый простой способ сделать это - переместить основную реализацию bar() и foo() в отдельные вспомогательные функции bar_unlocked() и foo_unlocked(), затем реализовать bar() и foo() как:

type foo(args)
{
    type result;

    pthread_mutex_lock(&barfoo_lock);
    result = foo_unlocked(args);
    pthread_mutex_unlock(&barfoo_lock);

    return result;
}

type bar(args)
{
    type result;

    pthread_mutex_lock(&barfoo_lock);
    result = bar_unlocked(args);
    pthread_mutex_unlock(&barfoo_lock);

    return result;
}

Вы можете безопасно звонить bar_unlocked() изнутри реализации foo_unlocked().

0 голосов
/ 21 мая 2019

Еще один способ сделать это с так называемым «реентрантным» или «рекурсивным» объектом мьютекса / блокировки.

https://en.cppreference.com/w/cpp/thread/recursive_mutex

Он работает точно так же, как обычная блокировказа исключением того, что вызов lock() из потока, который уже заблокировал его, будет успешным, а вызов unlock() не разблокирует мьютекс, пока поток не unlock() заблокирует блокировку столько разпоскольку он lock() редактировал блокировку.

Рекурсивные блокировки - это функция, которая появляется во многих различных многопоточных библиотеках, но я не знаю о библиотеке pthreads, поэтому, возможно, ответ @caf будетлучший выбор для вас.

...