IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 12.03.08 12:45
Оценка:
если использовать IOCP при обработке сокетов, то во многих примерах, в том числе и Jim Ohlund рекомендуют создать объект — структуру типа PER_HANDLE и ее адрес передавать в качестве CompletionKey при вызове CreateIoCompletionPort.
такой вопрос: а когда же удалять созданный объект?
что меня смущает — это то, что на один сокет может быть задействовано одновременно несколько асинхронных операций. если закрыть сокет, то GetQueuedCompletionStatus сработает несколько раз (для каждой операции). пока все overlapped не обработаются и не удалятся вроде бы как нельзя удалять эту PER_HANDLE.
а как отследить момент, что все операции по закрытому сокету закончились?
неужели безопасно через CompletionKey передавать только простые значения, которые помещаются в PULONG_PTR ?
Re: IOCP + CompletionKey - когда удалять объект?
От: Michael Chelnokov Украина  
Дата: 12.03.08 12:49
Оценка:
Здравствуйте, mr_trwister, Вы писали:

_>если использовать IOCP при обработке сокетов, то во многих примерах, в том числе и Jim Ohlund рекомендуют создать объект — структуру типа PER_HANDLE и ее адрес передавать в качестве CompletionKey при вызове CreateIoCompletionPort.

_>такой вопрос: а когда же удалять созданный объект?

Т.е. оно per-handle, то по закрытию этого handle.

_>что меня смущает — это то, что на один сокет может быть задействовано одновременно несколько асинхронных операций. если закрыть сокет, то GetQueuedCompletionStatus сработает несколько раз (для каждой операции). пока все overlapped не обработаются и не удалятся вроде бы как нельзя удалять эту PER_HANDLE.

_>а как отследить момент, что все операции по закрытому сокету закончились?

Проще всего — счетчиком.

_>неужели безопасно через CompletionKey передавать только простые значения, которые помещаются в PULONG_PTR ?


Ядру плевать, что ты там передаешь. Но ты сам-то как отличишь указатель на живой объект от указателя на уже удаленный?
Re[2]: IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 12.03.08 13:26
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


_>>если использовать IOCP при обработке сокетов, то во многих примерах, в том числе и Jim Ohlund рекомендуют создать объект — структуру типа PER_HANDLE и ее адрес передавать в качестве CompletionKey при вызове CreateIoCompletionPort.

_>>такой вопрос: а когда же удалять созданный объект?

MC>Т.е. оно per-handle, то по закрытию этого handle.


не все так просто =)
в момент закрытия handle нельзя сразу же удалять этот объект. он еще может быть должен жить некоторое время.
т.е. можно обозначить, что он должен быть удален не ранее, чем будет закрыть handle. но не более того.

_>>что меня смущает — это то, что на один сокет может быть задействовано одновременно несколько асинхронных операций. если закрыть сокет, то GetQueuedCompletionStatus сработает несколько раз (для каждой операции). пока все overlapped не обработаются и не удалятся вроде бы как нельзя удалять эту PER_HANDLE.

_>>а как отследить момент, что все операции по закрытому сокету закончились?

MC>Проще всего — счетчиком.


ага! каждая новая overlapped будет увеличивать счетчик, а ее удаление будет уменьшать. останется только потокобезопасность предусмотреть.

_>>неужели безопасно через CompletionKey передавать только простые значения, которые помещаются в PULONG_PTR ?


MC>Ядру плевать, что ты там передаешь. Но ты сам-то как отличишь указатель на живой объект от указателя на уже удаленный?


да я это понимаю. просто ни в одном примере я не встретил того, чтобы эту ситуацию как-либо учитывали.

что же получается — после закрытия handle удалять объект, если ссылок на него больше нет. а если есть, то оставить на откуп потоку в IOCP, чтобы последняя OVERLAPPED операция проверила счетчик и удалила? или вообще периодически пробегать по списку handle и чистить?
Re[3]: IOCP + CompletionKey - когда удалять объект?
От: Michael Chelnokov Украина  
Дата: 12.03.08 14:38
Оценка:
Здравствуйте, mr_trwister, Вы писали:

_>ага! каждая новая overlapped будет увеличивать счетчик, а ее удаление будет уменьшать. останется только потокобезопасность предусмотреть.


InterlockedIncrement/InterlockedDecrement, например.

_>что же получается — после закрытия handle удалять объект, если ссылок на него больше нет.


Нет, не удалять, а уменьшать счетчик на единицу. Счетчик при создании ставить в 1.

_>а если есть, то оставить на откуп потоку в IOCP, чтобы последняя OVERLAPPED операция проверила счетчик и удалила?


Не последняя. Перед началом любой операции увеличиваешь счетчик, по поступлению уведомления уменьшаешь. По достижению счетчиком нуля удаляешь объект. Специальный случай — невозможность начать операцию (вызов I/O вернул ошибку, и код ошибки не IO_PENDING). В этом случае надо уменьшить счетчик сразу, т.к. уведомления не будет.

_>или вообще периодически пробегать по списку handle и чистить?


Не, это некрасиво.
Re[4]: IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 12.03.08 16:40
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


_>>ага! каждая новая overlapped будет увеличивать счетчик, а ее удаление будет уменьшать. останется только потокобезопасность предусмотреть.


MC>InterlockedIncrement/InterlockedDecrement, например.


да. точно! спасибо.

_>>что же получается — после закрытия handle удалять объект, если ссылок на него больше нет.


MC>Нет, не удалять, а уменьшать счетчик на единицу. Счетчик при создании ставить в 1.


ээ.. а если счетчик уже равен 0, то оставлять что ли? если ссылок больше нет, то при закрытии сокета что еще делать остается?

_>>а если есть, то оставить на откуп потоку в IOCP, чтобы последняя OVERLAPPED операция проверила счетчик и удалила?


MC>Не последняя. Перед началом любой операции увеличиваешь счетчик, по поступлению уведомления уменьшаешь. По достижению счетчиком нуля удаляешь объект. Специальный случай — невозможность начать операцию (вызов I/O вернул ошибку, и код ошибки не IO_PENDING). В этом случае надо уменьшить счетчик сразу, т.к. уведомления не будет.


получается, что удаление объекта возможно в двух местах (мы ведь не исключаем, что сокет может быть создан, связан с IOCP, но никаких отложенных операций на нем в данный момент нет), а именно: изнутри потока, управляемого IOCP и из потока, который закрывает сокет.

_>>или вообще периодически пробегать по списку handle и чистить?


MC>Не, это некрасиво.
Re[5]: IOCP + CompletionKey - когда удалять объект?
От: Michael Chelnokov Украина  
Дата: 12.03.08 19:22
Оценка:
Здравствуйте, mr_trwister, Вы писали:

MC>>Нет, не удалять, а уменьшать счетчик на единицу. Счетчик при создании ставить в 1.

_>ээ.. а если счетчик уже равен 0, то оставлять что ли? если ссылок больше нет, то при закрытии сокета что еще делать остается?
...
_>получается, что удаление объекта возможно в двух местах (мы ведь не исключаем, что сокет может быть создан, связан с IOCP, но никаких отложенных операций на нем в данный момент нет), а именно: изнутри потока, управляемого IOCP и из потока, который закрывает сокет.

void Release() {
  if(InterlockedDecrement(&counter) == 0)
    delete object;
}


Вызываешь Release() после закрытия сокета и по получению (по окончанию обработки) уведомления. После вызова Release не рассчитывай что объект все еще жив, т.к. delete может быть вызван и в том и в другом случае, ты не знаешь точно в каком именно. В конструкторе объекта (вызываемого по открытию сокета) делаешь counter = 1.
Re[6]: IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 13.03.08 06:24
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


MC>>>Нет, не удалять, а уменьшать счетчик на единицу. Счетчик при создании ставить в 1.

_>>ээ.. а если счетчик уже равен 0, то оставлять что ли? если ссылок больше нет, то при закрытии сокета что еще делать остается?
MC>...
_>>получается, что удаление объекта возможно в двух местах (мы ведь не исключаем, что сокет может быть создан, связан с IOCP, но никаких отложенных операций на нем в данный момент нет), а именно: изнутри потока, управляемого IOCP и из потока, который закрывает сокет.

MC>
MC>void Release() {
MC>  if(InterlockedDecrement(&counter) == 0)
MC>    delete object;
MC>}
MC>


т.е. что-то типа метода Release и вызов внутри него delete this — так будет нормально?

MC>Вызываешь Release() после закрытия сокета и по получению (по окончанию обработки) уведомления. После вызова Release не рассчитывай что объект все еще жив, т.к. delete может быть вызван и в том и в другом случае, ты не знаешь точно в каком именно. В конструкторе объекта (вызываемого по открытию сокета) делаешь counter = 1.
Re: IOCP + CompletionKey - когда удалять объект?
От: Gomes Россия http://irazin.ru
Дата: 13.03.08 06:30
Оценка:
Здравствуйте, mr_trwister, Вы писали:

_>если использовать IOCP при обработке сокетов, то во многих примерах, в том числе и Jim Ohlund рекомендуют создать объект — структуру типа PER_HANDLE и ее адрес передавать в качестве CompletionKey при вызове CreateIoCompletionPort.

Только будь внимателен, в книжке они указатель к DWORD приводят, что сейчас недопустимо.
Re[2]: IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 13.03.08 08:51
Оценка:
Здравствуйте, Gomes, Вы писали:

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


_>>если использовать IOCP при обработке сокетов, то во многих примерах, в том числе и Jim Ohlund рекомендуют создать объект — структуру типа PER_HANDLE и ее адрес передавать в качестве CompletionKey при вызове CreateIoCompletionPort.

G>Только будь внимателен, в книжке они указатель к DWORD приводят, что сейчас недопустимо.

ага. я к ULONG_PTR привожу.
Re[7]: IOCP + CompletionKey - когда удалять объект?
От: Michael Chelnokov Украина  
Дата: 13.03.08 10:16
Оценка:
Здравствуйте, mr_trwister, Вы писали:

_>т.е. что-то типа метода Release и вызов внутри него delete this — так будет нормально?


Да. Или статическая, с явной передачей this.
Re[8]: IOCP + CompletionKey - когда удалять объект?
От: mr_trwister  
Дата: 13.03.08 11:36
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


_>>т.е. что-то типа метода Release и вызов внутри него delete this — так будет нормально?


MC>Да. Или статическая, с явной передачей this.


большое спасибо за советы!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.