I have a list of HANDLE's, controlled by a lot of different IO devices. What would be the (performance) difference between:
Is WaitForMultipleObjects O(n) time complex with n the amount of handles?
You can somehow call async_read on a windows::basic_handle right? Or is that assumption wrong?
If I call run on the same IO device in multiple threads, will the handling-calls be balanced between those threads? That would be a major benefit of using asio.
The WaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state until the conditions of the wait criteria have been met or the time-out interval elapses.
The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state until the object is signaled or the time-out interval elapses. The function modifies the state of some types of synchronization objects.
since it sounds like the main use you would derive from asio is the fact that it is built on top of IO completion ports (iocp for short). So, let's start with comparing iocp with WaitForMultipleObjects()
. These two approaches are essentially the same as select
vs. epoll
on linux.
The main drawback of WaitForMultipleObjects
that was solved by iocp is the inability to scale with many file descriptors. It is O(n), since for each event you receive you pass in the full array again, and internally WaitForMultipleObjects must scan the array to know which handles to trigger on.
However, this is rarely a problem because of the second drawback. WaitForMultipleObjects()
has a limit on the max number of handles it can wait on (MAXIMUM_WAIT_OBJECTS
). This limit is 64 objects (see winnt.h). There are ways around this limit by creating Event objects and tying multiple sockets to each event, and then wait on 64 events.
The third drawback is that there's actually a subtle "bug" in WaitForMultipleObjects()
. It returns the index of the handle which triggered an event. This means it can only communicate a single event back to the user. This is different from select
, which will return all file descriptors that triggered an event. WaitForMultipleObjects
scans the handles passed in to it and return the first handle that has its event raised.
This means, if you are waiting on 10 very active sockets, all of which has an event on them most of the time, there will be a very heavy bias toward servicing the first socket in the list passed in to WaitForMultipleObjects
. This can be circumvented by, every time the function returns and the event has been serviced, run it again with a timeout of 0, but this time only pass in the part of the array 1 past the event that triggered. Repeatedly until all handles has been visited, then go back to the original call with all handles and an actual timeout.
iocp solves all of these problems, and also introduces an interface for a more generic event notification, which is quite nice.
With iocp (and hence asio):
I'm not sure about your assumption of using async_read
on a custom handle. You might have to test that. If your handle refers to a socket, I would imagine it would work.
As for the threading question; yes. If you run()
the io_service
in multiple threads, events are dispatched to a free thread, and will scale with more threads. This is a feature of iocp, which even has a thread pool API.
In short: I believe asio or iocp would provide better performance than simply using WaitForMultipleObjects
, but whether or not that performance will benefit you mostly depends on how many handles you have and how active they are.
Both WaitForSingleObject
& WaitForMultipleObjects
are widely used functions, The WaitForSingleObject
function is used for waiting on a single Thread synchronization object. This is signaled when the object is set to signal or the time out interval is finished. If the time interval is INFINITE, it waits infinitely.
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
The WaitForMultipleObjects
is used to wait for multiple objects signaled. In the Semaphore thread synchronization object, when the counters go to zero the object is non-signaled. The Auto reset event and Mutex is non-signaled when it releases the object. The manual reset event does affect the wait functions' state.
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
If dwMilliseconds
is zero
, the function does not enter a wait state if the object is not signaled; it always returns immediately. If dwMilliseconds
is INFINITE
, the function will return only when the object is signaled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With