Changeset 00aa122


Ignore:
Timestamp:
Nov 24, 2025, 4:13:37 PM (6 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

Files:
3 edited
1 moved

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 )
  • tests/concurrency/futures/multi.cfa

    rfbaea970 r00aa122  
     1// DEPRECATED future type multi_future. Eventually remove this test.
     2
    13#include <thread.hfa>
    24#include <future.hfa>
  • tests/concurrency/futures/typed.cfa

    rfbaea970 r00aa122  
    88};
    99
    10 void ?{}( Server & this ) {
    11         this.cnt = 0;
    12         for(i; NFUTURES) {
    13                 this.requests[i] = 0p;
     10void ?{}( Server & server ) with( server ) {
     11        cnt = 0;
     12        for ( i; NFUTURES ) {
     13                requests[i] = 0p;
    1414        }
    1515}
    1616
    17 void ^?{}( Server & mutex this ) {
    18         assert(this.cnt == 0);
    19         for(i; NFUTURES) {
    20                 this.requests[i] = 0p;
     17void ^?{}( Server & mutex server ) with( server ) {
     18        assert( cnt == 0 );
     19        for ( i; NFUTURES ) {
     20                requests[i] = 0p;
    2121        }
    2222}
    2323
    24 void process( Server & this, int i ) {
    25         if( this.requests[i] == 0p ) return;
    26         single_future(int) * f = this.requests[i];
    27         this.requests[i] = 0p;
    28         this.cnt--;
    29         fulfil( *f , i);
     24void process( Server & server, int i ) with( server ) {
     25  if ( requests[i] == 0p ) return;
     26        single_future(int) * f = requests[i];
     27        requests[i] = 0p;
     28        cnt--;
     29        (*f)( i );                                                                                      // fulfil
    3030}
    3131
    32 void call( Server & mutex this, single_future(int) & f ) {
    33         for(i; NFUTURES) {
    34                 if( this.requests[i] == 0p ) {
    35                         this.requests[i] = &f;
    36                         this.cnt++;
     32void call( Server & mutex server, single_future(int) & f ) with( server ) {
     33        for ( i; NFUTURES ) {
     34                if ( requests[i] == 0p ) {
     35                        requests[i] = &f;
     36                        cnt++;
    3737                        return;
    3838                }
     
    4141}
    4242
    43 void main( Server & this ) {
     43void main( Server & server ) {
    4444        unsigned i = 0;
    45         for() {
    46                 waitfor( ^?{} : this ) {
     45        for () {
     46                waitfor ( ^?{} : server ) {
    4747                        break;
    48                 }
    49                 or when( this.cnt < NFUTURES ) waitfor( call: this ) {}
     48                } or when( server.cnt < NFUTURES ) waitfor( call : server ) {}
    5049                or else {
    51                         process( this, i % NFUTURES );
     50                        process( server, i % NFUTURES );
    5251                        i++;
    5352                }
    5453        }
    5554
    56         for(i; NFUTURES) {
    57                 process( this, i );
     55        for ( i; NFUTURES ) {
     56                process( server, i );
    5857        }
    5958}
     
    6261thread Worker {};
    6362
    64 void thrash(void) {
     63void thrash() {
    6564        volatile int locals[250];
    66         for(i; 250) {
     65        for ( i; 250 ) {
    6766                locals[i] = 0xdeadbeef;
    6867        }
    6968}
    7069
    71 void work(void) {
     70void work() {
    7271        single_future(int) mine;
    7372        call( *the_server, mine );
    74         wait( mine );
     73        mine();                                                                                         // get
    7574}
    7675
    7776void main( Worker & ) {
    78         for(150) {
     77        for ( 150 ) {
    7978                thrash();
    8079                work();
     
    8483
    8584int main() {
    86         printf( "start\n" );                            // non-empty .expect file
     85        printf( "start\n" );                                                            // non-empty .expect file
    8786        processor procs[2];
    8887        {
     
    9392                }
    9493        }
    95         printf( "done\n" );                             // non-empty .expect file
    96 
     94        printf( "done\n" );                                                                     // non-empty .expect file
    9795}
Note: See TracChangeset for help on using the changeset viewer.