Сон, удерживая boost :: interprocess :: scoped_lock, заставляет его никогда не освобождаться - PullRequest
2 голосов
/ 10 июня 2009

Я делаю 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, все будет работать. Зачем? Я не думал, что сон с заблокированным мьютексом навсегда заблокирует мьютекс.

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

Спасибо!

Ответы [ 2 ]

7 голосов
/ 10 июня 2009

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

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

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

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

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

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

0 голосов
/ 10 июня 2009

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

...