Repository navigation
Conversation
…used Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes.
|
| Layer / File(s) | Summary |
|---|---|
Retain the queue top during timed waits src/rpp/rpp/schedulers/new_thread.hpp, src/rpp/rpp/schedulers/run_loop.hpp |
Both wait paths retain the top schedulable with a shared_ptr and compare the current queue top with that object. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Possibly related PRs
- AlexInLog/ReactivePlusPlus#763: PR
#763added the timed waits and queue-top comparisons that this change updates.
Suggested reviewers: alexinlog
Merge Risk: 
Minimal · up to 5e55a
-
No actionable merge-blocking risk was identified in the scheduler lifetime fix.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed-
Full details: Title check
-
Explanation
The title "schedulers: keep the waited-for top alive so its address cannot be reused" matches the changeset. In both run_loop.hpp and new_thread.hpp, the code now holds a shared_ptr copy of the queue's top during the wait, and the wake predicate compares against that retained object. The title names the main change and its purpose. It is specific and avoids vague terms. It is also a single sentence of 12 words and 73 characters, within the length a teammate can scan easily.
-
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
A rabbit watches schedulers wait,
The top stays safe while clocks tick late.
Two queues compare the same held friend,
Then wake when waits or changes end.
The rabbit hops through code once more,
And leaves neat footprints by the door.
Comment @coderabbitai help to get the list of available commands.
BENCHMARK RESULTS (AUTOGENERATED)
|
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| Subscribe empty callbacks to empty observable | 590.46 ns | 1.31 ns | 1.87 ns | 0.70 | 1.65 ns |
| Subscribe empty callbacks to empty observable via pipe operator | 591.97 ns | 1.59 ns | 1.87 ns | 0.85 | 1.63 ns |
Sources
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| from array of 1 - create + subscribe + immediate | 1542.07 ns | 0.32 ns | 0.31 ns | 1.05 | 0.27 ns |
| from array of 1 - create + subscribe + current_thread | 2318.94 ns | 2.92 ns | 3.45 ns | 0.85 | 2.75 ns |
| concat_as_source of just(1 immediate) create + subscribe | 4836.64 ns | 261.40 ns | 128.23 ns | 2.04 | 97.27 ns |
| defer from array of 1 - defer + create + subscribe + immediate | 1654.62 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
| interval - interval + take(3) + subscribe + immediate | 4882.57 ns | 47.39 ns | 59.66 ns | 0.79 | 50.13 ns |
| interval - interval + take(3) + subscribe + current_thread | 7033.54 ns | 26.99 ns | 32.72 ns | 0.82 | 30.15 ns |
| from array of 1 - create + as_blocking + subscribe + new_thread | 35707.59 ns | 33276.79 ns | 34766.46 ns | 0.96 | 27591.74 ns |
| from array of 1000 - create + as_blocking + subscribe + new_thread | 45112.17 ns | 51563.29 ns | 56094.37 ns | 0.92 | 44351.27 ns |
| concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe | 7185.96 ns | 316.02 ns | 148.33 ns | 2.13 | 127.08 ns |
Filtering Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take(1)+subscribe | 2420.82 ns | 0.32 ns | 0.31 ns | 1.04 | 0.30 ns |
| immediate_just+filter(true)+subscribe | 1845.68 ns | 0.32 ns | 0.31 ns | 1.04 | 0.28 ns |
| immediate_just(1,2)+skip(1)+subscribe | 2265.67 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
| immediate_just(1,1,2)+distinct_until_changed()+subscribe | 1854.64 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
| immediate_just(1,2)+first()+subscribe | 2854.57 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
| immediate_just(1,2)+last()+subscribe | 2102.19 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
| immediate_just+take_last(1)+subscribe | 2433.42 ns | 17.17 ns | 18.05 ns | 0.95 | 16.22 ns |
| immediate_just(1,2,3)+element_at(1)+subscribe | 1849.86 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
Schedulers
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate scheduler create worker + schedule | 624.39 ns | 0.65 ns | 1.56 ns | 0.42 | 0.59 ns |
| current_thread scheduler create worker + schedule | 744.91 ns | 5.52 ns | 4.98 ns | 1.11 | 3.61 ns |
| current_thread scheduler create worker + schedule + recursive schedule | 1755.97 ns | 66.54 ns | 62.68 ns | 1.06 | 52.26 ns |
Transforming Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+map(v*2)+subscribe | 1840.16 ns | 0.32 ns | 0.31 ns | 1.04 | 0.29 ns |
| immediate_just+scan(10, std::plus)+subscribe | 2040.34 ns | 0.32 ns | 0.31 ns | 1.04 | 0.31 ns |
| immediate_just+flat_map(immediate_just(v*2))+subscribe | 5393.12 ns | 300.09 ns | 139.91 ns | 2.14 | 173.10 ns |
| immediate_just+buffer(2)+subscribe | 2507.56 ns | 12.59 ns | 13.72 ns | 0.92 | 15.83 ns |
| immediate_just+window(2)+subscribe + subscsribe inner | 4284.10 ns | 1947.81 ns | 1360.01 ns | 1.43 | 1115.56 ns |
Conditional Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take_while(false)+subscribe | 1817.05 ns | - | - | 0.00 | - |
| immediate_just+take_while(true)+subscribe | 1846.06 ns | 0.32 ns | 0.31 ns | 1.04 | 0.31 ns |
Utility Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(1)+subscribe_on(immediate)+subscribe | 4180.36 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
Combining Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe | 8314.84 ns | 343.81 ns | 157.06 ns | 2.19 | 168.21 ns |
| immediate_just(1) + merge_with(immediate_just(2)) + subscribe | 8109.29 ns | 346.36 ns | 162.67 ns | 2.13 | 173.23 ns |
| immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe | - | 313.61 ns | 145.78 ns | 2.15 | 148.63 ns |
| immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe | 8518.58 ns | 784.15 ns | 418.19 ns | 1.88 | 359.54 ns |
| immediate_just(1) + zip(immediate_just(2)) + subscribe | 4513.89 ns | 350.76 ns | 225.02 ns | 1.56 | 199.56 ns |
| immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe | 6768.68 ns | 509.48 ns | 239.71 ns | 2.13 | 234.34 ns |
Subjects
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| publish_subject with 1 observer - on_next | 93.91 ns | 46.84 ns | 14.79 ns | 3.17 | 12.98 ns |
| subscribe 100 observers to publish_subject | 349907.67 ns | 36918.66 ns | 17755.66 ns | 2.08 | 15813.20 ns |
| 100 on_next to 100 observers to publish_subject | 25907.64 ns | 19327.19 ns | 20388.50 ns | 0.95 | 25672.43 ns |
Scenarios
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| basic sample | 2690.17 ns | 13.47 ns | 13.38 ns | 1.01 | 18.52 ns |
| basic sample with immediate scheduler | 2690.16 ns | 4.88 ns | 5.59 ns | 0.87 | 13.88 ns |
| mix operators with disposables and without disposables | 11832.56 ns | 2072.57 ns | 1464.13 ns | 1.42 | 1529.51 ns |
| single disposable and looooooong indentity chain | 36429.55 ns | 2097.66 ns | 1074.46 ns | 1.95 | 4065.39 ns |
Aggregating Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+reduce(10, std::plus)+subscribe | 2099.74 ns | 0.32 ns | 0.31 ns | 1.04 | 0.27 ns |
Error Handling Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe | 3076.05 ns | 1020.08 ns | 1010.45 ns | 1.01 | 759.50 ns |
| create(on_error())+retry(1)+subscribe | 1261.66 ns | 277.84 ns | 131.00 ns | 2.12 | 107.44 ns |
ci-macos
General
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| Subscribe empty callbacks to empty observable | 551.36 ns | 0.52 ns | 0.49 ns | 1.06 | 0.57 ns |
| Subscribe empty callbacks to empty observable via pipe operator | 349.73 ns | 0.48 ns | 0.50 ns | 0.95 | 0.68 ns |
Sources
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| from array of 1 - create + subscribe + immediate | 773.20 ns | 0.32 ns | 0.34 ns | 0.94 | 0.38 ns |
| from array of 1 - create + subscribe + current_thread | 1053.90 ns | 3.62 ns | 3.93 ns | 0.92 | 4.76 ns |
| concat_as_source of just(1 immediate) create + subscribe | 2317.42 ns | 161.62 ns | 183.10 ns | 0.88 | 246.39 ns |
| defer from array of 1 - defer + create + subscribe + immediate | 844.31 ns | 0.34 ns | 0.36 ns | 0.94 | 0.48 ns |
| interval - interval + take(3) + subscribe + immediate | 2473.26 ns | 48.23 ns | 59.16 ns | 0.82 | 90.69 ns |
| interval - interval + take(3) + subscribe + current_thread | 2914.65 ns | 28.90 ns | 36.01 ns | 0.80 | 47.79 ns |
| from array of 1 - create + as_blocking + subscribe + new_thread | 30743.24 ns | 28187.50 ns | 26443.10 ns | 1.07 | 57113.14 ns |
| from array of 1000 - create + as_blocking + subscribe + new_thread | 35915.39 ns | 35696.86 ns | 31683.33 ns | 1.13 | 47496.23 ns |
| concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe | 3849.78 ns | 193.83 ns | 200.32 ns | 0.97 | 273.11 ns |
Filtering Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take(1)+subscribe | 1141.89 ns | 0.31 ns | 0.35 ns | 0.90 | 0.39 ns |
| immediate_just+filter(true)+subscribe | 818.78 ns | 0.30 ns | 0.46 ns | 0.66 | 0.43 ns |
| immediate_just(1,2)+skip(1)+subscribe | 1049.78 ns | 0.33 ns | 0.40 ns | 0.83 | 0.49 ns |
| immediate_just(1,1,2)+distinct_until_changed()+subscribe | 856.27 ns | 0.31 ns | 0.37 ns | 0.85 | 0.38 ns |
| immediate_just(1,2)+first()+subscribe | 1279.88 ns | 0.33 ns | 0.39 ns | 0.83 | 0.45 ns |
| immediate_just(1,2)+last()+subscribe | 1012.52 ns | 0.84 ns | 1.01 ns | 0.82 | 1.22 ns |
| immediate_just+take_last(1)+subscribe | 1212.85 ns | 0.31 ns | 0.41 ns | 0.75 | 0.49 ns |
| immediate_just(1,2,3)+element_at(1)+subscribe | 838.41 ns | 0.31 ns | 0.37 ns | 0.84 | 0.42 ns |
Schedulers
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate scheduler create worker + schedule | 294.29 ns | 0.49 ns | 0.56 ns | 0.88 | 1.63 ns |
| current_thread scheduler create worker + schedule | 427.66 ns | 3.89 ns | 4.42 ns | 0.88 | 8.60 ns |
| current_thread scheduler create worker + schedule + recursive schedule | 780.15 ns | 68.77 ns | 71.56 ns | 0.96 | 93.65 ns |
Transforming Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+map(v*2)+subscribe | 865.99 ns | 2.40 ns | 3.23 ns | 0.74 | 4.35 ns |
| immediate_just+scan(10, std::plus)+subscribe | 1027.97 ns | 0.33 ns | 0.36 ns | 0.94 | 0.38 ns |
| immediate_just+flat_map(immediate_just(v*2))+subscribe | 2519.12 ns | 219.47 ns | 209.37 ns | 1.05 | 246.92 ns |
| immediate_just+buffer(2)+subscribe | 1070.79 ns | 14.41 ns | 17.13 ns | 0.84 | 35.72 ns |
| immediate_just+window(2)+subscribe + subscsribe inner | 1986.76 ns | 987.97 ns | 1148.06 ns | 0.86 | 1420.35 ns |
Conditional Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take_while(false)+subscribe | 1010.72 ns | - | - | 0.00 | - |
| immediate_just+take_while(true)+subscribe | 790.71 ns | 0.29 ns | 0.39 ns | 0.76 | 0.76 ns |
Utility Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(1)+subscribe_on(immediate)+subscribe | 1896.61 ns | 1.75 ns | 1.94 ns | 0.90 | 2.42 ns |
Combining Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe | 3978.70 ns | 224.14 ns | 230.48 ns | 0.97 | 268.27 ns |
| immediate_just(1) + merge_with(immediate_just(2)) + subscribe | 3087.64 ns | 207.25 ns | 207.75 ns | 1.00 | 289.43 ns |
| immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe | - | 206.28 ns | 214.98 ns | 0.96 | 445.25 ns |
| immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe | 3669.04 ns | 516.69 ns | 505.87 ns | 1.02 | 955.53 ns |
| immediate_just(1) + zip(immediate_just(2)) + subscribe | 2501.90 ns | 321.88 ns | 292.92 ns | 1.10 | 379.88 ns |
| immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe | 3323.41 ns | 301.07 ns | 322.01 ns | 0.93 | 558.55 ns |
Subjects
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| publish_subject with 1 observer - on_next | 47.17 ns | 21.09 ns | 23.40 ns | 0.90 | 26.23 ns |
| subscribe 100 observers to publish_subject | 106120.80 ns | 14966.01 ns | 19641.53 ns | 0.76 | 21384.00 ns |
| 100 on_next to 100 observers to publish_subject | 32145.21 ns | 10627.50 ns | 12055.55 ns | 0.88 | 15183.07 ns |
Scenarios
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| basic sample | 1576.12 ns | 10.39 ns | 11.76 ns | 0.88 | 80.86 ns |
| basic sample with immediate scheduler | 1200.31 ns | 5.42 ns | 6.53 ns | 0.83 | 24.74 ns |
| mix operators with disposables and without disposables | 5954.23 ns | 1257.20 ns | 1547.47 ns | 0.81 | 2625.00 ns |
| single disposable and looooooong indentity chain | 19700.30 ns | 1538.31 ns | 2184.15 ns | 0.70 | 6764.53 ns |
Aggregating Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+reduce(10, std::plus)+subscribe | 968.36 ns | 0.31 ns | 0.36 ns | 0.86 | 0.49 ns |
Error Handling Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe | 3663.22 ns | 2823.76 ns | 3500.00 ns | 0.81 | 8535.34 ns |
| create(on_error())+retry(1)+subscribe | 690.34 ns | 165.53 ns | 204.52 ns | 0.81 | 237.16 ns |
ci-ubuntu-clang
General
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| Subscribe empty callbacks to empty observable | 268.58 ns | 0.65 ns | 0.65 ns | 1.00 | 0.56 ns |
| Subscribe empty callbacks to empty observable via pipe operator | 271.85 ns | 0.64 ns | 0.64 ns | 1.00 | 0.59 ns |
Sources
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| from array of 1 - create + subscribe + immediate | 569.60 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| from array of 1 - create + subscribe + current_thread | 791.37 ns | 4.05 ns | 4.04 ns | 1.00 | 3.54 ns |
| concat_as_source of just(1 immediate) create + subscribe | 2431.94 ns | 131.04 ns | 130.66 ns | 1.00 | 109.42 ns |
| defer from array of 1 - defer + create + subscribe + immediate | 808.23 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| interval - interval + take(3) + subscribe + immediate | 2255.79 ns | 58.74 ns | 58.73 ns | 1.00 | 50.66 ns |
| interval - interval + take(3) + subscribe + current_thread | 3203.53 ns | 31.15 ns | 31.10 ns | 1.00 | 28.34 ns |
| from array of 1 - create + as_blocking + subscribe + new_thread | 38411.17 ns | 34280.18 ns | 35051.18 ns | 0.98 | 25955.45 ns |
| from array of 1000 - create + as_blocking + subscribe + new_thread | 45746.00 ns | 41546.96 ns | 41557.71 ns | 1.00 | 29988.08 ns |
| concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe | 3766.11 ns | 149.64 ns | 148.81 ns | 1.01 | 125.02 ns |
Filtering Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take(1)+subscribe | 1230.59 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just+filter(true)+subscribe | 882.46 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just(1,2)+skip(1)+subscribe | 1138.42 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just(1,1,2)+distinct_until_changed()+subscribe | 918.07 ns | 0.33 ns | 0.32 ns | 1.04 | 0.31 ns |
| immediate_just(1,2)+first()+subscribe | 1421.82 ns | 0.31 ns | 0.31 ns | 1.01 | 0.27 ns |
| immediate_just(1,2)+last()+subscribe | 1050.40 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just+take_last(1)+subscribe | 1269.79 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just(1,2,3)+element_at(1)+subscribe | 909.92 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
Schedulers
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate scheduler create worker + schedule | 286.75 ns | 1.55 ns | 1.55 ns | 1.00 | 0.55 ns |
| current_thread scheduler create worker + schedule | 417.61 ns | 4.04 ns | 4.04 ns | 1.00 | 3.81 ns |
| current_thread scheduler create worker + schedule + recursive schedule | 875.91 ns | 57.80 ns | 57.71 ns | 1.00 | 46.03 ns |
Transforming Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+map(v*2)+subscribe | 883.39 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
| immediate_just+scan(10, std::plus)+subscribe | 1005.33 ns | 0.62 ns | 0.62 ns | 1.00 | 0.29 ns |
| immediate_just+flat_map(immediate_just(v*2))+subscribe | 2347.22 ns | 137.55 ns | 139.26 ns | 0.99 | 113.46 ns |
| immediate_just+buffer(2)+subscribe | 1589.96 ns | 14.00 ns | 14.00 ns | 1.00 | 12.50 ns |
| immediate_just+window(2)+subscribe + subscsribe inner | 2580.18 ns | 906.00 ns | 900.95 ns | 1.01 | 748.24 ns |
Conditional Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take_while(false)+subscribe | 896.45 ns | - | - | 0.00 | - |
| immediate_just+take_while(true)+subscribe | 887.40 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
Utility Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(1)+subscribe_on(immediate)+subscribe | 2066.19 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
Combining Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe | 3325.45 ns | 162.87 ns | 164.06 ns | 0.99 | 124.69 ns |
| immediate_just(1) + merge_with(immediate_just(2)) + subscribe | 3829.65 ns | 142.85 ns | 143.64 ns | 0.99 | 124.01 ns |
| immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe | - | 143.91 ns | 143.37 ns | 1.00 | 114.55 ns |
| immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe | 3472.31 ns | 379.40 ns | 381.48 ns | 0.99 | 308.17 ns |
| immediate_just(1) + zip(immediate_just(2)) + subscribe | 2304.65 ns | 203.54 ns | 216.27 ns | 0.94 | 154.22 ns |
| immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe | 3354.06 ns | 223.52 ns | 226.57 ns | 0.99 | 182.07 ns |
Subjects
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| publish_subject with 1 observer - on_next | 52.73 ns | 19.25 ns | 19.24 ns | 1.00 | 15.92 ns |
| subscribe 100 observers to publish_subject | 213964.20 ns | 17591.85 ns | 17385.22 ns | 1.01 | 14404.76 ns |
| 100 on_next to 100 observers to publish_subject | 39428.77 ns | 20348.86 ns | 20315.86 ns | 1.00 | 15146.97 ns |
Scenarios
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| basic sample | 1351.96 ns | 11.51 ns | 11.51 ns | 1.00 | 16.50 ns |
| basic sample with immediate scheduler | 1348.60 ns | 5.91 ns | 5.91 ns | 1.00 | 5.45 ns |
| mix operators with disposables and without disposables | 6643.31 ns | 1179.80 ns | 1192.77 ns | 0.99 | 1179.25 ns |
| single disposable and looooooong indentity chain | 27746.92 ns | 1242.02 ns | 1250.01 ns | 0.99 | 3772.23 ns |
Aggregating Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+reduce(10, std::plus)+subscribe | 1034.85 ns | 0.31 ns | 0.31 ns | 1.00 | 0.27 ns |
Error Handling Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe | 2272.52 ns | 1174.48 ns | 1183.77 ns | 0.99 | 889.71 ns |
| create(on_error())+retry(1)+subscribe | 691.52 ns | 138.85 ns | 138.49 ns | 1.00 | 116.30 ns |
ci-windows
General
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| Subscribe empty callbacks to empty observable | 556.07 ns | 2.16 ns | 2.16 ns | 1.00 | 1.85 ns |
| Subscribe empty callbacks to empty observable via pipe operator | 572.10 ns | 2.16 ns | 2.16 ns | 1.00 | 1.85 ns |
Sources
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| from array of 1 - create + subscribe + immediate | 1155.57 ns | 4.93 ns | 4.94 ns | 1.00 | 5.55 ns |
| from array of 1 - create + subscribe + current_thread | 1419.82 ns | 15.75 ns | 15.74 ns | 1.00 | 15.45 ns |
| concat_as_source of just(1 immediate) create + subscribe | 3696.46 ns | 174.60 ns | 174.62 ns | 1.00 | 178.05 ns |
| defer from array of 1 - defer + create + subscribe + immediate | 1180.65 ns | 5.24 ns | 5.24 ns | 1.00 | 5.24 ns |
| interval - interval + take(3) + subscribe + immediate | 3736.36 ns | 139.81 ns | 139.74 ns | 1.00 | 142.29 ns |
| interval - interval + take(3) + subscribe + current_thread | 3460.30 ns | 60.15 ns | 59.86 ns | 1.00 | 62.80 ns |
| from array of 1 - create + as_blocking + subscribe + new_thread | 123175.00 ns | 118700.00 ns | 120400.00 ns | 0.99 | 119788.89 ns |
| from array of 1000 - create + as_blocking + subscribe + new_thread | 132655.56 ns | 135675.00 ns | 136975.00 ns | 0.99 | 137275.00 ns |
| concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe | 5329.67 ns | 206.57 ns | 201.39 ns | 1.03 | 215.13 ns |
Filtering Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take(1)+subscribe | 1818.86 ns | 19.42 ns | 19.42 ns | 1.00 | 21.36 ns |
| immediate_just+filter(true)+subscribe | 1610.58 ns | 18.50 ns | 18.51 ns | 1.00 | 21.59 ns |
| immediate_just(1,2)+skip(1)+subscribe | 2008.80 ns | 17.89 ns | 17.91 ns | 1.00 | 21.60 ns |
| immediate_just(1,1,2)+distinct_until_changed()+subscribe | 1328.95 ns | 20.67 ns | 20.68 ns | 1.00 | 26.86 ns |
| immediate_just(1,2)+first()+subscribe | 2372.16 ns | 18.20 ns | 18.21 ns | 1.00 | 19.43 ns |
| immediate_just(1,2)+last()+subscribe | 1464.98 ns | 19.13 ns | 19.15 ns | 1.00 | 22.84 ns |
| immediate_just+take_last(1)+subscribe | 2023.02 ns | 64.85 ns | 64.93 ns | 1.00 | 70.17 ns |
| immediate_just(1,2,3)+element_at(1)+subscribe | 1622.12 ns | 20.97 ns | 20.98 ns | 1.00 | 21.63 ns |
Schedulers
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate scheduler create worker + schedule | 477.39 ns | 4.32 ns | 4.32 ns | 1.00 | 4.32 ns |
| current_thread scheduler create worker + schedule | 648.68 ns | 11.11 ns | 11.11 ns | 1.00 | 11.11 ns |
| current_thread scheduler create worker + schedule + recursive schedule | 1079.50 ns | 103.96 ns | 101.36 ns | 1.03 | 103.12 ns |
Transforming Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+map(v*2)+subscribe | 1328.23 ns | 18.80 ns | 18.80 ns | 1.00 | 21.63 ns |
| immediate_just+scan(10, std::plus)+subscribe | 1422.12 ns | 20.96 ns | 20.96 ns | 1.00 | 23.80 ns |
| immediate_just+flat_map(immediate_just(v*2))+subscribe | 3837.33 ns | 186.30 ns | 185.11 ns | 1.01 | 223.46 ns |
| immediate_just+buffer(2)+subscribe | 2291.50 ns | 64.26 ns | 63.51 ns | 1.01 | 72.33 ns |
| immediate_just+window(2)+subscribe + subscsribe inner | 3974.07 ns | 1216.92 ns | 1192.15 ns | 1.02 | 1226.57 ns |
Conditional Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+take_while(false)+subscribe | 1305.28 ns | 17.57 ns | 17.57 ns | 1.00 | 19.13 ns |
| immediate_just+take_while(true)+subscribe | 1329.92 ns | 18.50 ns | 18.50 ns | 1.00 | 21.60 ns |
Utility Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(1)+subscribe_on(immediate)+subscribe | 3205.02 ns | 11.10 ns | 11.11 ns | 1.00 | 11.11 ns |
Combining Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe | 5054.46 ns | 197.43 ns | 195.27 ns | 1.01 | 222.13 ns |
| immediate_just(1) + merge_with(immediate_just(2)) + subscribe | 5710.11 ns | 186.78 ns | 178.89 ns | 1.04 | 204.81 ns |
| immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe | - | 195.15 ns | 194.65 ns | 1.00 | 199.56 ns |
| immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe | 6119.16 ns | 444.60 ns | 443.65 ns | 1.00 | 489.05 ns |
| immediate_just(1) + zip(immediate_just(2)) + subscribe | 3865.37 ns | 538.25 ns | 519.56 ns | 1.04 | 516.04 ns |
| immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe | 4853.97 ns | 314.42 ns | 314.38 ns | 1.00 | 325.14 ns |
Subjects
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| publish_subject with 1 observer - on_next | 36.72 ns | 29.42 ns | 29.27 ns | 1.01 | 30.01 ns |
| subscribe 100 observers to publish_subject | 264250.00 ns | 25013.33 ns | 25450.00 ns | 0.98 | 24830.23 ns |
| 100 on_next to 100 observers to publish_subject | 51881.82 ns | 35939.39 ns | 35922.58 ns | 1.00 | 32997.22 ns |
Scenarios
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| basic sample | 1853.25 ns | 96.57 ns | 96.80 ns | 1.00 | 112.11 ns |
| basic sample with immediate scheduler | 1857.89 ns | 66.73 ns | 68.51 ns | 0.97 | 82.35 ns |
| mix operators with disposables and without disposables | 9381.75 ns | 1787.22 ns | 1797.99 ns | 0.99 | 2439.19 ns |
| single disposable and looooooong indentity chain | 25641.46 ns | 1655.18 ns | 1630.37 ns | 1.02 | 6267.21 ns |
Aggregating Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| immediate_just+reduce(10, std::plus)+subscribe | 1458.16 ns | 19.11 ns | 19.11 ns | 1.00 | 22.83 ns |
Error Handling Operators
| name | rxcpp | rpp | prev rpp | ratio | rpp no optimization |
|---|---|---|---|---|---|
| create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe | 1896.36 ns | 357.24 ns | 353.06 ns | 1.01 | 380.86 ns |
| create(on_error())+retry(1)+subscribe | 1721.11 ns | 138.15 ns | 137.92 ns | 1.00 | 139.85 ns |
Follow-up to the review point in #763.
While
run_loopandnew_threadwait for the top of their queue, the wake-up predicate compares the current top with the waited-for one. The waited-for top was kept only as a raw pointer. If another thread popped and released it, a newly queued schedulable could get the same address. The predicate would then miss the change and the worker would sleep until the old deadline, and the comparison used a dangling pointer.Change. Both workers keep a
std::shared_ptrcopy of the waited-for top for the duration of the wait and comparetop().get()against it. While the copy exists, the address cannot be reused. Two files, 8 insertions, 4 deletions.Tests (GCC 14.2, Debian trixie; gRPC, Qt and asio tests not built):
100% tests passed, 0 tests failed out of 49test_schedulerunder ThreadSanitizer: 12 of 12 test cases, 153 of 153 assertions, no warningCHECK( 50134984ns < 1s ),CHECK( 50145671ns < 1s )🤖 Generated with Claude Code
Summary by CodeRabbit