Re[4]: Completion Port + KeInsertQueue + управление очередью
От: Геннадий Майко США  
Дата: 27.01.09 08:26
Оценка:
Здравствуйте, abdul.zycor,

AZ>Допустим такая ситуация, как я описал выше.

AZ>Да рабочие потоки после возврата управления из GetQueuedCompletionStatus делают что-то типа
AZ>
AZ>                        if(GetQueuedCompletionStatus(ThreadPool->CompletionPort, &NumberOfBytes, (PULONG_PTR)&WorkItem, (LPOVERLAPPED *)&Overlapped, INFINITE)) {
AZ>                        //проверка флага окончания работы рабочего потока
AZ>            if ( InterlockedCompareExchange(&ThreadPool->fDestroyCalled, 1, 1) ) {
AZ>                status = ERROR_SUCCESS;
AZ>                break;
AZ>            }
AZ>

AZ>т.е. на данные WorkItem они забивают и прекрастно завершаются досрочно, прекращая выбирать данные из очереди, но очередь не пуста ведь остается.
--
Я тоже думал над этим и предлагаю попробовать следующий подход для корректного окончания потоков и одновременного очищения очереди. Идея такая:

1. Для окончания работы основной поток устанваливает команду в общей структуре (на которую указывает CompletionKey) и помещает в очередь N "остановочных" completion packet с помощью функции PostQueuedCompletionStatus, где N — число потоков. После этого никакие запросы на передачу данных с помощью этого completion port'a не делаются. Это нужно для того, чтобы в очереди последние N completion packet'ы были "остановочными".

2. Все потоки, кроме последнего, заканчивают свою работу, получив соответствующую команду через эту общую структуру. Для этого в этой же структуре необходимо иметь счетчик заканчивающихся потоков. Каждый поток, определив, что ему пора заканчиваться, аккуратно декрементирует этот счетчик, и, проанализировав его, "понимает", последний ли он или нет.

3. Все потоки должны также каким-то образом идентифицировать "остановочный" пакет и аккуратно уменьшать еще один счетчик "остановочных" пакетов в той же самой структуре. Сделать это можно многими способами (например, передавая NULL в качестве lpOverlapped в функции PostQueuedCompletionStatus).

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

C уважением,
Геннадий Майко.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.