2011-09-16 3 views
1

У меня довольно простое приложение, которое загружает файлы в поток. Эта нить использует WinINet APIs, и начинается так:Как избежать полного использования ЦП или прекратить работу, в то время как InternetOpenURL пытается (и не удается) подключиться?

HINTERNET hInternet = InternetOpen(strUserAgent.c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
    DWORD dwFlags = INTERNET_FLAG_NO_UI | INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD; 
    HINTERNET hUrl = InternetOpenUrl(hInternet, m_strURL.c_str(), L"", 0, dwFlags, NULL); 

Однако, если нет подключения к Интернету, или удаленный узел вниз, InternetOpenUrl займет много времени тайм-аут и полным. Хотя он делает это, то есть только в ситуации, когда он не может подключиться к удаленному хосту, он будет использовать от 80 до 100% одного процессора, пока он, наконец, не вернется. Это может продолжаться в течение минуты или около того из-за установки задержки таймаута. В одной системе , несмотря на настройки тайм-аута (см. Ниже), это продолжалось до десяти минут.

Как я:

  • Избегай такое использование массивного CPU, когда он просто пытается подключиться?
  • Сигнал потока для завершения, если я хочу закрыть приложение? Обычно тайм-аут прекрасен, но если приложение нужно закрыть, то он будет ждать окончания этого потока, который тратит много центрального процессора, делая очень мало внутри InternetOpenUrl.

[В сторону: Текущие настройки тайм-аута на моей системе, как показали InternetQueryOption:

  • INTERNET_OPTION_CONNECT_TIMEOUT: 60s
  • INTERNET_OPTION_RECEIVE_TIMEOUT: 30s
  • INTERNET_OPTION_SEND_TIMEOUT: 30s

Изменение этих уменьшит время до того, как метод сдастся и вернется, и таким образом уменьшит время, затраченное на использование большого количества CPU, но может повлиять на соединение. В конце концов, тайм-ауты существуют по какой-то причине. Это приложение может использоваться в ситуациях с нечетным подключением, например на борту корабля, где подключение может потенциально заходить на спутник с высокой задержкой и занимать больше времени, чем стандартное подключение к Интернету. Я не знаю, какие разумные тайм-ауты будут. Кроме того, должен быть лучший способ избежать использования ЦП и прекратить работу быстрее, чем просто сократить таймауты.]

+0

Это странно. Вы сталкиваетесь с проблемой заражения ЦП на многих компьютерах или только на вашем? Я не ожидаю такого поведения от WinInet. –

+0

Это на два по крайней мере: Windows 7 на машине WMWare Fusion (моя - она ​​только накачивает до 80% на моей) и Windows XP (я думаю) на второй машине (штат сотрудников QA). –

+0

Вы пытались использовать WinInet в асинхронном режиме? –

ответ

1

Вы можете использовать WinInet в asynchronous mode. Не уверен, решает ли он проблему использования ЦП, но завершение может быть выполнено правильно.

+0

Читая документацию, это похоже на самый безопасный вариант для меня. У меня нет времени, чтобы попробовать, прежде чем истекает срок, но это звучит неплохо, так что сделайте себе несколько очков! –

+0

@David, асинхронный режим не поможет в вашем случае, хотя его рекомендуемый способ использования библиотеки WinINet. В вашем случае InternetOpenUrl занимает время, поэтому в асинхронном режиме вы также не сможете завершить функцию, если не закроете дескриптор сеанса. – Vishal

+0

@ Vishal, InternetOpenUrl не должен блокироваться в асинхронном режиме. –

1

Я думаю, вы можете закрыть дескриптор сеанса, возвращенный из InternetOpen с помощью InternetCloseHandle.

В соответствии с http://msdn.microsoft.com/en-us/library/aa384350(v=VS.85).aspx он разблокирует любую ожидающую операцию на этом ручке.

Так что если вы сохраняете InternetOpenUrl в отдельном потоке, вы все равно можете закрыть дескриптор сеанса из родительского потока (отдельный поток не требуется, если вы используете его в режиме async). Вы можете установить функцию обратного вызова статуса для любой очистки ресурсов.

Если вы хотите установить другой тайм-аут, используйте InternetSetOption.

PS: Это было какое-то время, когда я делал что-либо с библиотекой WinINet, поэтому я не могу гарантировать, что вышеуказанный метод будет работать.

+0

Интересно, поэтому я бы назвал InternetOpenUrl, но передал его, вернувшись в основной поток, который может закрыть его? –

+0

Что я сказал, вы можете сохранить InternetOpenUrl в отдельном потоке, и когда вы хотите остановить операцию, закройте дескриптор HINTERNET, который вы поставили в качестве первого аргумента в основном потоке. – Vishal