Changeset 00aa122
- Timestamp:
- Nov 24, 2025, 4:13:37 PM (6 hours ago)
- Branches:
- master
- Parents:
- fbaea970
- Files:
-
- 3 edited
- 1 moved
-
libcfa/src/concurrency/future.hfa (modified) (4 diffs)
-
tests/concurrency/futures/.expect/multi.txt.off (moved) (moved from tests/concurrency/futures/.expect/multi.txt )
-
tests/concurrency/futures/multi.cfa (modified) (1 diff)
-
tests/concurrency/futures/typed.cfa (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/future.hfa
rfbaea970 r00aa122 10 10 // Created On : Wed Jan 06 17:33:18 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Nov 23 22:48:08202513 // Update Count : 2 0812 // Last Modified On : Mon Nov 24 16:08:52 2025 13 // Update Count : 222 14 14 // 15 15 … … 100 100 except = 0p; 101 101 state = FUTURE_EMPTY$; 102 lock{};103 102 } 104 103 … … 320 319 321 320 //-------------------------------------------------------------------------------------------------------- 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 328 324 //-------------------------------------------------------------------------------------------------------- 329 325 330 326 forall( T ) { 327 // PUBLIC 328 331 329 struct single_future { 332 330 inline future_t; … … 335 333 336 334 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 1 3 #include <thread.hfa> 2 4 #include <future.hfa> -
tests/concurrency/futures/typed.cfa
rfbaea970 r00aa122 8 8 }; 9 9 10 void ?{}( Server & this) {11 this.cnt = 0;12 for (i; NFUTURES) {13 this.requests[i] = 0p;10 void ?{}( Server & server ) with( server ) { 11 cnt = 0; 12 for ( i; NFUTURES ) { 13 requests[i] = 0p; 14 14 } 15 15 } 16 16 17 void ^?{}( Server & mutex this ){18 assert( this.cnt == 0);19 for (i; NFUTURES) {20 this.requests[i] = 0p;17 void ^?{}( Server & mutex server ) with( server ) { 18 assert( cnt == 0 ); 19 for ( i; NFUTURES ) { 20 requests[i] = 0p; 21 21 } 22 22 } 23 23 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);24 void 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 30 30 } 31 31 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++;32 void 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++; 37 37 return; 38 38 } … … 41 41 } 42 42 43 void main( Server & this) {43 void main( Server & server ) { 44 44 unsigned i = 0; 45 for () {46 waitfor ( ^?{} : this) {45 for () { 46 waitfor ( ^?{} : server ) { 47 47 break; 48 } 49 or when( this.cnt < NFUTURES ) waitfor( call: this ) {} 48 } or when( server.cnt < NFUTURES ) waitfor( call : server ) {} 50 49 or else { 51 process( this, i % NFUTURES );50 process( server, i % NFUTURES ); 52 51 i++; 53 52 } 54 53 } 55 54 56 for (i; NFUTURES) {57 process( this, i );55 for ( i; NFUTURES ) { 56 process( server, i ); 58 57 } 59 58 } … … 62 61 thread Worker {}; 63 62 64 void thrash( void) {63 void thrash() { 65 64 volatile int locals[250]; 66 for (i; 250) {65 for ( i; 250 ) { 67 66 locals[i] = 0xdeadbeef; 68 67 } 69 68 } 70 69 71 void work( void) {70 void work() { 72 71 single_future(int) mine; 73 72 call( *the_server, mine ); 74 wait( mine );73 mine(); // get 75 74 } 76 75 77 76 void main( Worker & ) { 78 for (150) {77 for ( 150 ) { 79 78 thrash(); 80 79 work(); … … 84 83 85 84 int main() { 86 printf( "start\n" ); // non-empty .expect file85 printf( "start\n" ); // non-empty .expect file 87 86 processor procs[2]; 88 87 { … … 93 92 } 94 93 } 95 printf( "done\n" ); // non-empty .expect file 96 94 printf( "done\n" ); // non-empty .expect file 97 95 }
Note:
See TracChangeset
for help on using the changeset viewer.