17.01.2023 23:31 Alf P. Steinbach kirjutas:
> I wonder if there is some not too dang complex way to do the equivalent
> of the following Windows-specific class just using the C++ standard
> library, or maybe it's there already?
>
>
> class Signal:
> public Movable
> {
> HANDLE m_event_handle;
>
> public:
> ~Signal() { ::CloseHandle( m_event_handle ); }
>
> Signal():
> m_event_handle( ::CreateEvent( nullptr, false, false,
> nullptr ) )
> {
> hopefully( m_event_handle != 0 ) or $fail( "CreateEvent
> failed" );
> }
>
> Signal( Signal&& other ):
> m_event_handle( exchange( other.m_event_handle, +HANDLE() ) )
> {}
>
> auto handle() const -> HANDLE { return m_event_handle; }
> void send() { ::SetEvent( m_event_handle ); }
> };
>
This class can be easily implemented in terms of a std::mutex, a boolean
flag and a std::condition_variable. Alas, that would not make use of
Windows Event objects (for starters, Events are kernel objects and thus
way too slow), so there is no way it can return a Windows event handle
which you need below.
There is Boost.Interprocess but I'm not aware if any of its classes wrap
a Windows Event, and if they expose its handle.
> Much of the point is that the signaling can be done /before/ the
> waiting. But also after a wait has started. I.e. at any time.
>
> Example usage, in some code to wait for console keyboard input:
>
>
> struct Event_kind{ enum Enum{ console_event, signal }; };
>
> void wait_for_events()
> {
> ::WaitForSingleObject( stream_handle::in, INFINITE )
> >> $expected( retval == WAIT_OBJECT_0 )
> or $fail( "::WaitForSingleObject failed unexpectedly." );
> }
>
> auto wait_for_events_or( in_<Signal> abort_request_signal )
> -> Event_kind::Enum
> {
> const HANDLE handles[] =
> {
> stream_handle::in,
> abort_request_signal.handle()
> };
> constexpr int begin_ok_range = WAIT_OBJECT_0;
> constexpr int end_ok_range = begin_ok_range + int_size_of(
> handles );
> const int retval = ::WaitForMultipleObjects( int_size_of(
> handles ), handles, false, INFINITE );
What becomes cumbersome is to combine std::condition_variable with a
wait on keyboard input. WaitForMultipleObjects() is very Windows-specific.
First you should come up with how to wait for keyboard input in standard
C++, then we can see how one can abort this wait.
Boost.asio might provide something like this, it has e.g.
basic_stream_socket::cancel(). But boost.asio is not yet in the
standard, and wrapping keyboard input into an asio stream would also
require some custom platform-specific code as far as I can see.