Collin Dauphinee
Collin Dauphinee

Reputation: 14003

How can I wait on an I/O completion port and an event at the same time?

Is there any possible way to achieve this?

For instance, I have an I/O completion port that 10 worker threads are pulling tasks out of. Each task is associated with an object. Some objects cannot be worked on concurrently, so if one thread is working with one of these objects and a second thread pulls out a task that requires this object, the second thread has to wait for the first to complete.

As a work around, objects could have an event that gets signaled upon release. If a thread is 'stuck' because the task is received requires a locked object, it could wait on either the locked object to be released, or for a new task to be queued. If it picks up a new task, it will push the task it couldn't work on back into the queue.

I am aware of alternative approaches, but this seems like functionality that should exist. Can this be achieved with Windows API?

Upvotes: 5

Views: 2022

Answers (3)

Jan Ringoš
Jan Ringoš

Reputation: 141

Associate the Event object with IOCP, and get I/O Completion when it gets signalled, using NtAssociateWaitCompletionPacket. It's supported on Windows 8 and later.

See example here: https://github.com/tringi/win32-iocp-events

Upvotes: 1

Len Holgate
Len Holgate

Reputation: 21644

Change your design.

Add an internal task queue to the object. Then when a task is posted to the IOCP have the IOCP thread place the task in the object's task queue and, if no other thread is "processing" tasks for this object have this IOCP thread mark the object as being processed and begin processing the task; (lock per object queue, add task, check if we should be the processing thread, unlock the queue) and either process the task in the object or return to the IOCP.

When another thread has a task for the same object it also goes through the same process. Note that the thread processing the object DOES NOT hold a lock on the object's task queue so the new IOCP thread can add the task to the object's queue and then see that a thread is already processing and simply return to the IOCP.

Once the thread has finished the current task it checks the object's task queue again and either continues processing the next task, or, if the queue is empty, marks the object as not processing and returns to the IOCP.

This prevents you blocking IOCP threads on tasks which can't yet run and maintains locality of data to the thread that happens to be processing at the time.

The one potential issue is that you can have some always busy objects starving others but you can avoid this by simply checking how many tasks you have processed and it if exceeds a tunable max then pushing the next task to process back into the IOCP so that other objects have a chance.

Upvotes: 3

David Schwartz
David Schwartz

Reputation: 182893

The idea solution is to have a thread wait for the event and post to the completion port when the event occurs. Alternatively, have a thread wait for the event and just handle it. If you have two fundamentally different things you need to do, use two threads to do them.

Upvotes: 1

Related Questions