Переход в спящий режим при удержании boost::interprocess::scoped_lock приводит к тому, что он никогда не будет выпущен

StackOverflow https://stackoverflow.com/questions/977265

Вопрос

Я делаю IPC на Linux используя boost::interprocess::shared_memory_object согласно ссылка (пример анонимного мьютекса).

Существует серверный процесс, который создает shared_memory_object и записывает в него, держа в руке interprocess_mutex завернутый в scoped_lock;и клиентский процесс, который печатает все, что написал другой - в данном случае это int.

Я столкнулся с проблемой:если сервер переходит в спящий режим, удерживая мьютекс, клиентский процесс никогда не сможет получить его и ждет вечно.

Багги сервер петля:

using namespace boost::interprocess;
int n = 0;
while (1) {
    std::cerr << "acquiring mutex... ";
    {
        // "data" is a struct on the shared mem. and contains a mutex and an int
        scoped_lock<interprocess_mutex> lock(data->mutex);
        data->a = n++;
        std::cerr << n << std::endl;
        sleep(1);
    } // if this bracket is placed before "sleep", everything works
}

Сервер выходной сигнал:

acquiring mutex... 1
acquiring mutex... 2
acquiring mutex... 3
acquiring mutex... 4

Клиент петля:

while(1) {
   std::cerr << "acquiring mutex... ";
   {
      scoped_lock<interprocess_mutex> lock(data->mutex);
      std::cerr << data->a << std::endl;
   }
   sleep(1);
}

Клиент вывод (ожидает вечно):

acquiring mutex...

Дело в том, что если я переместу скобку на строку перед sleep звоните, все работает.Почему?Я не думал, что сон с заблокированным мьютексом приведет к тому, что мьютекс будет заблокирован навсегда.

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

Спасибо!

Это было полезно?

Решение

Ваша теория верна.

Если вы посмотрите на нижнюю часть примера анонимного мьютекса в ссылке, на которую вы ссылались, вы увидите

Как мы можем видеть, мьютекс полезен для защиты данных, но не для уведомления другого процесса о событии.

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

Перемещение сервера sleep() вне области видимости означает, что он переходит в спящий режим, пока мьютекс свободен, давая клиенту возможность запустить и приобрести мьютекс для себя.

Попробуйте позвонить sched_yield() (Только для Linux), если вы хотите отказаться от процессора, но все еще находитесь в режиме ожидания в пределах своей компетенции. sleep(0) тоже может сработать.

Другие советы

спать, удерживая мьютекс, неправильно.Мьютекс защищает некоторые данные (т. е.data-> a) и область действия должна быть сведена к минимуму при чтении / записи этих данных.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top