• Re: A futex'd once_flag that is failable

    From Bonita Montero@Bonita.Montero@gmail.com to ger.ct,comp.lang.c++ on Thu Dec 11 15:44:59 2025
    From Newsgroup: comp.lang.c++

    Sorry, should go here.

    Am 11.12.2025 um 15:43 schrieb Bonita Montero:
    Niche, isn't it ?


    #pragma once
    #include <atomic>
    #include <concepts>

    template<typename Callable>
    -a -a requires requires( Callable callable ) { { callable() } -> std::same_as<void>; }
    -a -a -a -a || requires( Callable callable ) { { callable() } -> std::convertible_to<bool>; }
    void xcall_once( std::atomic_int &flag, Callable callable )
    {
    -a -a using namespace std;
    -a -a for( int ref = flag.load( memory_order_acquire ); )
    -a -a {
    -a -a -a -a if( ref > 0 )
    -a -a -a -a -a -a return;
    -a -a -a -a if( ref < 0 )
    -a -a -a -a {
    -a -a -a -a -a -a flag.wait( ref, memory_order_relaxed );
    -a -a -a -a -a -a ref = flag.load( memory_order_acquire );
    -a -a -a -a -a -a continue;
    -a -a -a -a }
    -a -a -a -a if( flag.compare_exchange_strong( ref, -1,
    memory_order_relaxed, memory_order_relaxed ) )
    -a -a -a -a -a -a break;
    -a -a }
    -a -a bool succ = true;
    -a -a if constexpr( requires( Callable callable ) { { callable() } -> same_as<void>; } )
    -a -a -a -a callable();
    -a -a else
    -a -a -a -a succ = (bool)callable();
    -a -a flag.store( (int)succ, memory_order_release );
    -a -a flag.notify_all();
    }


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Thu Dec 11 19:54:53 2025
    From Newsgroup: comp.lang.c++

    This is the final code:

    #pragma once
    #include <concepts>
    #include <atomic>

    struct xonce_flag
    {
    -a -a xonce_flag() noexcept = default;
    private:
    -a -a friend bool xcall_once( xonce_flag &, std::invocable auto );
    -a -a std::atomic<signed char> m_flag = 0;
    };

    bool xcall_once( xonce_flag &xflag, std::invocable auto callable )
    {
    -a -a using namespace std;
    -a -a atomic<signed char> &flag = xflag.m_flag;
    -a -a for( signed char ref = flag.load( memory_order_acquire ); ; )
    -a -a -a -a if( ref > 0 )
    -a -a -a -a -a -a return true;
    -a -a -a -a else if( ref < 0 )
    -a -a -a -a {
    -a -a -a -a -a -a flag.wait( ref, memory_order_relaxed );
    -a -a -a -a -a -a ref = flag.load( memory_order_acquire );
    -a -a -a -a -a -a continue;
    -a -a -a -a }
    -a -a -a -a else if( flag.compare_exchange_strong( ref, -1, memory_order_relaxed, memory_order_acquire ) )
    -a -a -a -a -a -a break;
    -a -a bool succ = true;
    -a -a try
    -a -a {
    -a -a -a -a if constexpr( requires { (bool)callable(); } )
    -a -a -a -a -a -a succ = (bool)callable();
    -a -a -a -a else
    -a -a -a -a -a -a callable();
    -a -a }
    -a -a catch( ... )
    -a -a {
    -a -a -a -a flag.store( 0, memory_order_release );
    -a -a -a -a flag.notify_all();
    -a -a -a -a throw;
    -a -a }
    -a -a flag.store( (signed char)succ, memory_order_release );
    -a -a flag.notify_all();
    -a -a return succ;
    }

    --- Synchronet 3.21a-Linux NewsLink 1.2