C ++: Как реализовать время ожидания для произвольного вызова функции? - PullRequest
27 голосов
/ 19 мая 2009

Мне нужно вызвать библиотечную функцию, которая иногда не завершается в течение заданного времени, к сожалению. Есть ли способ вызвать функцию, но отменить ее, если она не завершается в течение n секунд?

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

Возможно ли возможно запустить его как (буст) поток, который я затем смогу завершить через определенное время? Будет ли что-то подобное работать? Я на самом деле считаю, что функция не поточно-ориентированная, но это не имеет значения, если я запускаю ее как only single thread, верно? Есть ли другие (лучшие) решения?

Ответы [ 9 ]

18 голосов
/ 19 мая 2009

Вы можете вызвать boost::thread для вызова API:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}

Boost не позволяет вам уничтожить рабочий поток. В этом примере он просто осиротел.

Вы должны быть осторожны с тем, что делает этот вызов API, потому что он может никогда не высвободить полученные ресурсы.

15 голосов
/ 19 мая 2009

Я думаю, что единственный безопасный способ сделать это - создать отдельный процесс sandbox , который вызывает функцию библиотеки как прокси для вашего приложения. Вам нужно будет реализовать какой-то тип IPC между вашим приложением и прокси. Внедрение тайм-аута при чтении ответа IPC тогда довольно тривиально. Если при чтении происходит сбой из-за тайм-аута, вы можете безопасно прекратить работу прокси-сервера, не рискуя работоспособностью вашего приложения.

8 голосов
/ 19 мая 2009

То, о чем вы говорите, обычно называется «сторожевой» системой. Сторожевой таймер, как правило, является вторым потоком, который проверяет состояние всех других потоков. Сторожевой таймер обычно настроен на периодическую работу. Если от других потоков не было получено ответа, сторожевой таймер может уведомить пользователя или даже убить нарушающий поток, если это возможно сделать безопасно (зависит от вашего приложения).

3 голосов
/ 20 мая 2009

Проблема в том, что с внутрипроцессным решением без поддержки функции вы можете получить потенциально недопустимое состояние.

Пример. Когда вы прерываете поток во время выделения памяти, ваша куча процесса может быть повреждена.

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

Вы можете, как предлагает Бен Штрауб, просто осиротеть поток: поставить его на самый низкий приоритет и позволить ему работать бесконечно. Это, конечно, только ограниченное решение: если поток потребляет ресурсы (вероятно), они замедляют работу системы, также существует ограничение на количество потоков на процесс (обычно из-за адресного пространства для стека потоков).

Как правило, я бы предпочел решение для внешнего процесса. Простой шаблон таков:
Запишите входные данные в файл, запустите внешний процесс с файлом в качестве аргумента. Внешний процесс записывает ход выполнения (если есть) в файл на диске, который можно отслеживать, и может даже позволить процессу возобновиться с того места, с которого он был запущен. Результаты записываются на диск, и родительский процесс может их читать.

Когда вы завершаете процесс, вам все равно приходится иметь дело с синхронизацией доступа к внешним ресурсам (например, файлам), а также с тем, как обращаться с заброшенными перехватчиками, наполовину записанными файлами и т. Д. Но это, как правило, ПУТЬ к надежному решению.

3 голосов
/ 19 мая 2009
3 голосов
/ 19 мая 2009

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

1 голос
/ 09 декабря 2011

"Мне нужно вызвать библиотечную функцию, которая иногда не завершается в течение заданного времени, к сожалению. Есть ли способ вызвать функцию, но прервать ее, если она не завершится в течение n секунд?"

Короткий ответ - нет. Обычно это проблема ... Сам вызов должен завершиться в какое-то время (реализуя свой собственный тайм-аут), но блокирование вызовов обычно является проблемой (например, gethostbyname ()), потому что тогда это до их (или системного) таймаута, а не вашего. *

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

Личные предпочтения, в высокодоступных системах мне нравится, когда мои потоки часто вращаются (хотя и не заняты блокировкой) с определенными таймаутами, вызовом неблокирующих функций и с точными условиями выхода на месте. Глобальная или зависящая от потока переменная 'done' помогает добиться чистого выхода.

1 голос
/ 22 мая 2009

Перейти к процессу Orphan, запустить его и время его выполнения. Если время истекает, вызовите ОС, чтобы убить его.

Как избежать гоночных гонок. по этому шаблону:

  • создать файл для хранения в args (конечно, все передается как VAL). Сиротскому процессу разрешено только чтение данных из этого файла.

  • Сирота обрабатывает входные данные, создает выходной файл со значениями результатов и закрывает его.

  • Только когда все сделано, сирота удаляет входной файл, факт, который сигнализирует основному процессу, что работа была выполнена.

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

1 голос
/ 19 мая 2009

Вам нужен поток и Future Object , который может содержать результат вызова функции.

Пример использования наддува см. здесь .

Вам нужно будет проверить будущее после тайм-аута, и, если оно не установлено, действовать соответственно.

...