Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Standard C++ thread sync object that you can wait for being signaled, like Windows' Event?

18 views
Skip to first unread message

Alf P. Steinbach

unread,
Jan 17, 2023, 4:32:00 PM1/17/23
to
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 ); }
};


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 );
hopefully( begin_ok_range <= retval and retval < end_ok_range )
or $fail( "::WaitForMultipleObjects failed unexpectedly." );
const int handles_index = retval - WAIT_OBJECT_0;
return static_cast<Event_kind::Enum>( handles_index );
}


Probably a standard library based thing can't be interfaced with
Windows' synchronization, but if it could that would be cool.


- Alf

Chris M. Thomasson

unread,
Jan 17, 2023, 4:40:36 PM1/17/23
to
On 1/17/2023 1:31 PM, Alf P. Steinbach wrote:
> 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?
[...]

Study up on condition variables.

Alf P. Steinbach

unread,
Jan 17, 2023, 5:44:53 PM1/17/23
to
Yes, I use them, but as I understand it a condition variable doesn't
remember that it's been signaled.

- Alf

Scott Lurndal

unread,
Jan 17, 2023, 6:23:02 PM1/17/23
to
If it is used properly, it doesn't need to.

Chris M. Thomasson

unread,
Jan 17, 2023, 9:00:30 PM1/17/23
to
A condition variable depends on its state. You are in full control of
said state.

Chris M. Thomasson

unread,
Jan 17, 2023, 9:22:12 PM1/17/23
to
Fwiw, imvho, condition variables are a heck of a lot more "flexible"
than windows events. Creating a windows event (think auto-reset for now)
from a condvar and its state, is doable. Creating a condvar from windows
event's is a nightmare...

Chris M. Thomasson

unread,
Jan 17, 2023, 10:35:58 PM1/17/23
to
Think of conditional waiting on a predicate. Read Programming with Posix
Threads by David Butenhof...

James Kuyper

unread,
Jan 18, 2023, 1:36:58 AM1/18/23
to
That would be a far more useful comment if accompanied with an
explanation of how to use one properly, despite the fact that it doesn't
remember. You could, in particular, use the code provided in the
original message, and show how to implement it using standard C++ threads.


Chris M. Thomasson

unread,
Jan 18, 2023, 1:56:08 AM1/18/23
to
If you are trying to model a semaphore, what would be predicate be for
decrementing it? Keep in mind that a thread must wait when it tries to
decrement a semaphore with a count that is less than one... There are
other ways to implement a semaphore, but the predicate must hold.

Now think of a binary semaphore. This is basically a windows auto reset
event.

Chris M. Thomasson

unread,
Jan 18, 2023, 2:13:40 AM1/18/23
to
Have you ever seen the Benaphore? This can be implemented in pure std C++:

https://www.haiku-os.org/legacy-docs/benewsletter/Issue1-26.html

Paavo Helde

unread,
Jan 18, 2023, 7:50:55 AM1/18/23
to
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.






Scott Lurndal

unread,
Jan 18, 2023, 10:10:37 AM1/18/23
to
Yes, I suppose I could have, had I the time. They key word here is 'predicate'
which in and of itself generally encodes the 'signaled' state of the
condition variable. I did find VMS event flags useful back in the day,
to be sure, but haven't found any use for the windows version; having
never had the desire to program under windows.
0 new messages