IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 08.08.07 21:05
Оценка:
Доброго времени суток.
Есть задача реализовать IOCP.
Создал порт:
hCompletionPort = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 2);

"2" поставил ручками, руководствуясь
[msdn]Maximum number of threads that the operating system can allow to concurrently process I/O completion packets for the I/O completion port
[/msdn]
т.к. хочу таки протестить на двух потоках, а проц в машине один

потом навесил на него созданные сокеты
::CreateIoCompletionPort((HANDLE)pSocket->GetSocket(), m_hCompletionPort, (ULONG_PTR)((Socket*)pSocket), 0);


Запустил два потока:

int Run()
{
......
......

BOOL bIORet = ::GetQueuedCompletionStatus(hCompletionPort, &unIoSize, (LPDWORD)&pSocket, &pOverlapped, 5000);
if (!bIORet)  
{
}
else
{
//обработка данных
}
....
.....
return 0;
}


Проблема. При одном потоке все работает прекрасно, при двух я ооочень часто не получаю READ, т.е. как будто до меня не доходит пакет. GetQueuedCompletionStatus просто провисает по таймауту во всех потоках. Но! Если поставить брейк-поинт на хотя бы "if (!bIORet)", то новые пакеты я получать начну (старые уже никогда ). Посылка при любом количестве потоков успешна. Как быть?
Re: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 08.08.07 21:50
Оценка:
Делаю одному потоку с помощью Process Explorer Suspend — работает, снимаю с паузы — не работает..
Re: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 07:16
Оценка:
1. Сокет у Вас создается с флагом WSA_FLAG_OVERLAPPED? ( если Вы используете вызов socket, то флаг установлен )
2. Данные читаются с помощью WSARecv, куда передается 6ым параметром пустая структура OVERLAPPED и эта структура остается валидной до окончания операции? Если эта структура используется многократно, ее нужно обновлять ( обнулять ) перед каждым использованием.
3. Вы учитываете, что операция чтения может быть выполнена синхронно?
4. Мне честно говоря немного смущает вот это:
(LPDWORD)&pSocket, &pOverlapped
Если p — это префикс указателя, то разыменование указателя в данном случае IMHO не уместно?
Да пребудет с тобою сила
Re[2]: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 09.08.07 08:58
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>1. Сокет у Вас создается с флагом WSA_FLAG_OVERLAPPED? ( если Вы используете вызов socket, то флаг установлен )

Именно так.

::WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);


TC>2. Данные читаются с помощью WSARecv, куда передается 6ым параметром пустая структура OVERLAPPED и эта структура остается валидной до окончания операции? Если эта структура используется многократно, ее нужно обновлять ( обнулять ) перед каждым использованием.


Обнуления действительно не было. Добавил, проверю.

TC>3. Вы учитываете, что операция чтения может быть выполнена синхронно?

Поясните, пожалуйста.

TC>4. Мне честно говоря немного смущает вот это:

TC>(LPDWORD)&pSocket, &pOverlapped
TC>Если p — это префикс указателя, то разыменование указателя в данном случае IMHO не уместно?

С разыменованием думаю проблем нет. Указатель на объект "Сокет" отдаю так

BOOL bSuccess = ::PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD)pSocket, &pOverlapBuff->m_ol);

//pOverlapBuff поинтер на объект такого вида;
//class OverlapBuff
//{
//public:
//.......
//.......
//    OVERLAPPED m_ol;
//    WSABUF m_wsabuf;
//.......
//.......
//};
Re[2]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 09:20
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>3. Вы учитываете, что операция чтения может быть выполнена синхронно?


В этом случае все равно уведомление будет.
Re[3]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 09:24
Оценка:
Здравствуйте, mLapo, Вы писали:

L>BOOL bSuccess = ::PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD)pSocket, &pOverlapBuff->m_ol);


Кстати, а что этим делается?
Re[4]: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 09.08.07 10:05
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

MC>Здравствуйте, mLapo, Вы писали:


L>>BOOL bSuccess = ::PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD)pSocket, &pOverlapBuff->m_ol);


MC>Кстати, а что этим делается?


например, посылка данных в сокет.

bool Socket::SendBuffer()
{
//создаем буффер, обнуляем поле "OVERLAPPED m_ol".
    OverlapBuff* pOverlapBuff = new OverlapBuff();

//заполняем "WSABUF m_wsabuf";
    pOverlapBuff->SetupWrite((char*)get_buffer(), get_data_size());
    return TRUE == ::PostQueuedCompletionStatus(m_IOCompletitionPort, 0, (DWORD)this, &pOverlapBuff->m_ol);
}


после этого жду нотификации, что Send прошел в IOCP потоке.
Понятно, что буферы на отправку/получение обложены критическими секциями, но локировки в этих местах нет.

Конкретно
BOOL bSuccess = ::PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD)pSocket, &pOverlapBuff->m_ol);

инициирует ожидание получения данных сразу после создания сокета

Вот и все.
Re[5]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 11:12
Оценка:
Здравствуйте, mLapo, Вы писали:

L>например, посылка данных в сокет.


А где WSASend?
Re[3]: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 11:21
Оценка:
TC>>3. Вы учитываете, что операция чтения может быть выполнена синхронно?
MC>В этом случае все равно уведомление будет.
Это понятно, но может быть какая то логическая ошибка, типа

status = WSARecv
if ( status == STATUS_PENDING )
{
GetQueueCompletionStatus
}

Да пребудет с тобою сила
Re[5]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 11:24
Оценка:
Здравствуйте, mLapo, Вы писали:

L>инициирует ожидание получения данных сразу после создания сокета


А это еще зачем? Ты не хочешь чтобы WSARecv вызывалась в этом потоке?
Re[5]: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 11:28
Оценка:
У меня стойкое ощущение, что Вы не понимаете назначение функции или используете ее не самым очевидным способом PostQueuedCompletionStatus. Советую почитать маны. В обычном случае, это функция не очень то нужна. Мне на ум приходит такой сценарий использования ( говорим про отправку данных ) IOCP:

void
sending_thread() 
{
   do {
  
   //получаем уведомление о завершившейся операции записи. Это значит что в этот сокет можно еще накидать данных
   GetQueueCompleteionStatus

   //кидаем данные
   WSASend

  } while( 1 );

}


Таких потоков можно создать несколько. И никаких PostQueuedCompletionStatus.
Да пребудет с тобою сила
Re[4]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 11:33
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>Это понятно, но может быть какая то логическая ошибка, типа


Да, там скорее всего автор запутался в последовательностях происходящих событий/вызовов. С его множеством PostQueuedCompletionStatus это неудивительно.

For mLapo: Вообще-то PostQueuedCompletionStatus обычно используется в том случае, когда надо "завернуть" на IOCP нечто, изначально IOCP не поддерживающее. Например, у тебя уже есть некий черный ящик, который уведомляет о происходящем через какие-нибудь callback'и. Ты не хочешь для него плодить отдельных потоков, а хочешь чтобы уведомления от него обрабатывались в пуле потоков-обработчиков IOCP. Тогда и стОит использовать PostQueuedCompletionStatus. Частный случай такого черного ящика — команды SCM Windows-сервису.
Re[5]: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 09.08.07 12:34
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:
MC>Здравствуйте, TarasCo, Вы писали:
TC>>Это понятно, но может быть какая то логическая ошибка, типа
MC>Да, там скорее всего автор запутался в последовательностях происходящих событий/вызовов. С его множеством PostQueuedCompletionStatus это неудивительно.
MC>For mLapo: Вообще-то PostQueuedCompletionStatus обычно используется в том случае, когда надо "завернуть" на IOCP нечто, изначально IOCP не поддерживающее. Например, у тебя уже есть некий черный ящик, который уведомляет о происходящем через какие-нибудь callback'и. Ты не хочешь для него плодить отдельных потоков, а хочешь чтобы уведомления от него обрабатывались в пуле потоков-обработчиков IOCP. Тогда и стОит использовать PostQueuedCompletionStatus. Частный случай такого черного ящика — команды SCM Windows-сервису.

Во-первых, спасибо вам за конструктивный диалог. C IOCP не работал раньше, может где-то и туплю.
Переписал код, сделав ненужными PostQueuedCompletionStatus.
Вначале была такая схема.
Мне нужно отправить данные:
1) В рабочем потоке создаю OverlapBuff с пометкой "IWrite".
2) В рабочем потоке вызываю PostQueuedCompletionStatus передав туда сокет, который хочет отправить и pOverlapBuff
3) В потоке IOCP отлавливаю IWrite, достаю из прараметров GetQueuedCompletionStatus сокет, после чего вызываю WSASend с необходимыми параметрами среди которых и "новый" рOverlapBuff, но уже с пометкой "IWriteComplete".
4) по получению IWriteComplete некоторым образом обновляю буфер сокета.

С получением в принципе все тоже самое, только после получения данных я снова иницирую чтение вызвав WSARead

pOverlapBuff->SetOperation(IOReadCompleted);
pOverlapBuff->SetupRead((char*)pSocket->ReadBuffer()->get_buffer() + pSocket->ReadBuffer()->get_data_size(), pSocket->ReadBuffer()->get_free_size());
uint32 dwIoSize = 0;
uint32 ulFlags = MSG_PARTIAL;
if(::WSARecv(pSocket->GetSocket(), pOverlapBuff->GetWSABuffer(), 1, &dwIoSize,  &ulFlags, &pOverlapBuff->m_ol, NULL) == SOCKET_ERROR


Переписал.
Теперь при желании отправить данные, буду сразу слать и ждать нотификации об успешной отправке. С получение тоже самое. Без PostQueuedCompletionStatus. Буду тестировать.
Re[6]: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 13:14
Оценка:
У меня вопрос немного офтопик: Вы с UDP что ли работаете?
Да пребудет с тобою сила
Re[7]: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 09.08.07 13:27
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>У меня вопрос немного офтопик: Вы с UDP что ли работаете?


Нет, с TCP..
А к чему вопрос?
Re[8]: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 14:23
Оценка:
L>А к чему вопрос?
тогда этого не надо — MSG_PARTIAL
Да пребудет с тобою сила
Re[8]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 14:25
Оценка:
Здравствуйте, mLapo, Вы писали:

L>А к чему вопрос?


Подозреваю что к тому что, судя по твоему описанию, тебе наплевать на возможное перемешивание отправляемых данных.
Re[9]: IOCP: GetQueuedCompletionStatus и потоки
От: mLapo  
Дата: 09.08.07 14:40
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

MC>Здравствуйте, mLapo, Вы писали:


L>>А к чему вопрос?


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

Нет, данные не перемешиваются. Пока не получено подтверждения об отправке (WriteComplete), новые данные лишь добавляются к буферу. После получения подтверждения, я проверяю буфер на наличие данных, если оные существуют инициирую следующую отправку.
На перемешивание и многократную посылку одних и тех же данных уже наступил
Re[10]: IOCP: GetQueuedCompletionStatus и потоки
От: Michael Chelnokov Украина  
Дата: 09.08.07 14:59
Оценка:
Здравствуйте, mLapo, Вы писали:

L>На перемешивание и многократную посылку одних и тех же данных уже наступил


Offtopic: Честно говоря, я в последние годы солидарен с противниками потоков. В начале всё прекрасно и просто. Потом оказывается что не учел возможности что-то испортить в параллельных потоках. Потом, после того как защитил всё что надо и что не надо, оказывается что существуют дедлоки. После убирания ненужных защит оказывается что данные снова портятся. И так далее по кругу. После нескольких кругов останавливаешься и думаешь — "ну и зачем мне нужны были эти потоки?". И так до следующего проекта
Однако, мы под Windows. Тут это "естественно"...
Re[11]: IOCP: GetQueuedCompletionStatus и потоки
От: TarasCo  
Дата: 09.08.07 15:24
Оценка:
MC>Offtopic: Честно говоря, я в последние годы солидарен с противниками потоков.

Я самый главный противник потоков . Многопоточный сетевой сервер — это штука для большой нагрузки. Но у нас все разработчики считают, что если соединений больше одного — нужна масштабирующаяся система. И начинается... В половине случаев IMHO можно обойтись моделью — принял соединение, обработал запрос, отдал данные, закрыл соединение, заснул в ожидании следующего. Возросла нагрузка и начались лаги? Купите 4-х процессорный сервер и руками админа запустите 4 экземпляра. Но у нас как и во всем — нужна машина — только 3л полный привод, дом — кирпичный трех-этажный, сервер — круче чем Oracle .
Да пребудет с тобою сила
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.