Ignore:
Timestamp:
Nov 24, 2025, 4:13:37 PM (20 hours ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Parents:
fbaea970
Message:

harmonize single_future with other future types, remove multi_future, marks its test as deprecated, and turn off its test

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/future.hfa

    rfbaea970 r00aa122  
    1010// Created On       : Wed Jan 06 17:33:18 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Nov 23 22:48:08 2025
    13 // Update Count     : 208
     12// Last Modified On : Mon Nov 24 16:08:52 2025
     13// Update Count     : 222
    1414//
    1515
     
    100100                        except = 0p;
    101101                        state = FUTURE_EMPTY$;
    102                         lock{};
    103102                }
    104103
     
    320319
    321320//--------------------------------------------------------------------------------------------------------
    322 // These futures below do not support waituntil statements so they may not have as many features as 'future'
    323 //  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
    324 //  since it uses raw atomics and no locks
    325 //
    326 // As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
    327 //  since it is monitor based and also is not compatible with waituntil statement.
     321// This future does not support waituntil statements so it does not have as many features as 'future'.
     322// However, it is cheap and cheerful and is more performant than 'future' since it uses raw atomics
     323// and no locks
    328324//--------------------------------------------------------------------------------------------------------
    329325
    330326forall( T ) {
     327        // PUBLIC
     328
    331329        struct single_future {
    332330                inline future_t;
     
    335333
    336334        static inline {
    337                 // Reset future back to original state
    338                 void reset(single_future(T) & this) { reset( (future_t&)this ); }
    339 
    340                 // check if the future is available
    341                 bool available( single_future(T) & this ) { return available( (future_t&)this ); }
    342 
    343                 // Mark the future as abandoned, meaning it will be deleted by the server
    344                 // This doesn't work beause of the potential need for a destructor
    345                 // void abandon( single_future(T) & this );
    346 
    347                 // Fulfil the future, returns whether or not someone was unblocked
    348                 thread$ * fulfil( single_future(T) & this, T result ) {
    349                         this.result = result;
    350                         return fulfil( (future_t&)this );
    351                 }
    352 
    353                 // Wait for the future to be fulfilled
    354                 // Also return whether the thread had to block or not
    355                 [T, bool] wait( single_future(T) & this ) {
    356                         bool r = wait( (future_t&)this );
    357                         return [this.result, r];
    358                 }
    359 
    360                 // Wait for the future to be fulfilled
    361                 T wait( single_future(T) & this ) {
    362                         [T, bool] tt;
    363                         tt = wait( this );
    364                         return tt.0;
    365                 }
    366         }
    367 }
    368 
    369 forall( T ) {
    370         monitor multi_future {
    371                 inline future_t;
    372                 condition blocked;
    373                 bool has_first;
    374                 T result;
    375         };
    376 
    377         static inline {
    378                 void ?{}(multi_future(T) & this) {
    379                         this.has_first = false;
    380                 }
    381 
    382                 bool $first( multi_future(T) & mutex this ) {
    383                         if ( this.has_first ) {
    384                                 wait( this.blocked );
    385                                 return false;
    386                         }
    387 
    388                         this.has_first = true;
    389                         return true;
    390                 }
    391 
    392                 void $first_done( multi_future(T) & mutex this ) {
    393                         this.has_first = false;
    394                         signal_all( this.blocked );
    395                 }
    396 
    397                 // Reset future back to original state
    398                 void reset(multi_future(T) & mutex this) {
    399                         if ( this.has_first != false ) abort("Attempting to reset a multi_future with at least one blocked threads");
    400                         if ( ! empty( this.blocked ) ) abort("Attempting to reset a multi_future with multiple blocked threads");
    401                         reset( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    402                 }
    403 
    404                 // Fulfil the future, returns whether or not someone was unblocked
    405                 bool fulfil( multi_future(T) & this, T result ) {
    406                         this.result = result;
    407                         return fulfil( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) ) != 0p;
    408                 }
    409 
    410                 // Wait for the future to be fulfilled
    411                 // Also return whether the thread had to block or not
    412                 [T, bool] wait( multi_future(T) & this ) {
    413                         bool sw = $first( this );
    414                         bool w = !sw;
    415                         if ( sw ) {
    416                                 w = wait( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    417                                 $first_done( this );
    418                         }
    419 
    420                         return [this.result, w];
    421                 }
    422 
    423                 // Wait for the future to be fulfilled
    424                 T wait( multi_future(T) & this ) {
    425                         return wait( this ).0;
    426                 }
    427         }
    428 }
     335                // PUBLIC
     336
     337                bool available( single_future(T) & fut ) { return available( (future_t &)fut ); } // future result available ?
     338
     339                // Return a value/exception from the future.
     340                [T, bool] get( single_future(T) & fut ) { return [fut.result, wait( fut )]; }
     341                T get( single_future(T) & fut ) { wait( fut ); return fut.result; }
     342                T ?()( single_future(T) & fut ) { return get( fut ); }  // alternate interface
     343
     344                // Load a value into the future, returns whether or not waiting threads.
     345                bool fulfil( single_future(T) & fut, T result ) {
     346                        fut.result = result;
     347                        return fulfil( (future_t &)fut ) != 0p;
     348                }
     349                bool ?()( single_future(T) & fut, T val ) { return fulfil( fut, val ); } // alternate interface
     350
     351                void reset( single_future(T) & fut ) { reset( (future_t &)fut ); } // mark future as empty (for reuse)
     352        } // static inline
     353} // forall( T )
Note: See TracChangeset for help on using the changeset viewer.