Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
Не совсем так. Я постараюсь далее показать на цифрах... 22.08.08 09:17 Число просмотров: 2333
Автор: void <Grebnev Valery> Статус: Elderman Отредактировано 22.08.08 09:28 Количество правок: 2
|
> > Нет не сильно, но теоретически дольше. > Даже не теоретически, а реально дольше. Но это такие > копейки по сравнению с остальным, что даже говорить как-то.
Не совсем так. Я постараюсь далее показать на цифрах. Ключевой поинт - если завершение операции синхронное (в данном случае), то поток может вычитывать данные из системного кэша (которые туда поместил драйвер) без переключения контекста. Это не аргумент?
> Это в простом случае. А вот такой момент: в одном потоке ты > вызываешь WSARecv с синхронным завершением (и логикой > обработки сразу), и одновременно в другом у тебя > срабатывает GetQueuedCompletionStatus на этот приход. Что > делать?
А сам-то что думаешь, что делать? Давай на минуту отвлечёмся от темы топика. Пусть, как я написал в реализации функции read (DWORD bytes_to_read) (см. в начале нитки), все запросы обрабатываются, как асинхронные (т.е имеем стандартное решение, когда количество полученных байт берётся из OVEPLAPPED::InternalHigh по завершению ::GetQueuedCompletionStatus(...), и нет этой ). Пусть мы имеем 4CPU и число конкурерентных потоков разрешённых использовать IOCP - 8. Тогда с большой вероятностью два или более потока (на разных CPU) могут одновременно обрабатывать разные pending issue из очереди IOCP для одно и того же сокета вне всякой последовательности:
1) Клиент посылает пакеты 1Mb + 1 Mb + ...
2) Драйвер получил данные (0.5Mb) и поместил issue в очередь IOCP
3) Поток 1 получил данные (0.5Mb) на ::GetQueuedCompletionStatus(...), начал обработку и .... произошло переключение контекста потока. Ужос !
4) Драйвер получил данные (0.3Mb) и поместил issue в очередь IOCP
5) Поток 8 получил данные (0.3Mb) на ::GetQueuedCompletionStatus(...), начал обработку и .... с радостью продолжил поломав при этом последовательность байт (поток 1 ещё не закончил или даже не начинал). Ужос !
6) Потоки 2,3,4,5,6,7 такого натворят, что только держись.
Чтобы прекратить это безобразие, я бы сделал так (кстати это решает вопрос, что делать, если во время синхронной обработки придёт завершение pending I/O):
static DWORD WINAPI worker_thread_proc(LPVOID lParam)
{
Socket_overlapped_acceptor& acceptor =reinterpret_cast<Socket_overlapped_acceptorgt;(lParam);
DWORD num_bytes = 0;
ULONG_PTR comp_key = 0;
OVERLAPPED* poverlapped = NULL;
while ( false == acceptor.m_exit_pool_thread_flag /* in addition to ::PostQueuedCompletionStatus(m_completion_port, 0, CK_EXIT_THREAD, NULL) for all the threads*/)
{
BOOL fOk = ::GetQueuedCompletionStatus(acceptor.m_completion_port, &num_bytes, &comp_key, &poverlapped, IOCP_TIMEOUT);
if(fOk)
{
...
...
if (comp_key == CK_READ)
{
bool queue_next_overlapped_request = true;
_ASSERT(poverlapped);
Client_proxy_connector* connector = static_cast<Client_proxy_connector*>(poverlapped);
Lock lock(&connector->m_cs);
do
{
// Call of the function "connector->read()" returns false, if there has been an I/O error.
// Read operation returns true in two cases:
// - socket connector has read all the data requested (reading is completed).
// - socket connector has partially read data; there are some data left (I/O pending).
if(false == connector->read(CONNECTOR_PACKET_SIZE))
{
LOG("Failed reading data from the connector.");
acceptor.release_client(connector);
break;
}
else if(true == connector->is_io_completed() )
{
if (connector->is_on_command())
{
// The command is OK. Proceed the command and read next one.
}
else
{
LOG("Error: invalid command.");
acceptor.release_client(connector);
break;
}
}
else
{
// IO pending. Wait for IO completion on ::GetQueuedCompletionStatus(...)
queue_next_overlapped_request = false;
}
}
while (true == queue_next_overlapped_request);
}
...
...
}
else
{
// TO DO on error
}
}
return (0);
}
---
Поправь, если я не прав.
> В общем не ломай голову над несуществующей проблемой :)
Немного поломаю що :( Я не могу кансельнуть дубликаты issues на IOCP для операций которые завершились синхронно. ::CancelIo((HANDLE) m_socket) не помогает.
|
|
|