-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit c3d6d99
authored
fix: ensure consistent schedulers across threads by removing ThreadStatic in RxSchedulers (#4192)
### Summary
Remove `ThreadStatic` from `RxSchedulers.MainThreadScheduler` and
`RxSchedulers.TaskpoolScheduler` so that schedulers are **process-wide
singletons** instead of **thread-local** values.
### Motivation / Context
When `RxSchedulers` was introduced, both `MainThreadScheduler` and
`TaskpoolScheduler` were marked `[ThreadStatic]`. Unlike the pre-split
`RxApp` (where only the **unit test** fields were thread-static), this
made the production schedulers **thread-local**. The result:
* Accessing `RxSchedulers.MainThreadScheduler`/`TaskpoolScheduler` from
different threads could return **different instances**.
* Switching threads (or running in environments with multiple app
domains/contexts) could cause the value to **“reset” back to defaults**,
leading to subtle behavior changes and flakiness.
This regressed the previous behavior where production schedulers were
app-global, and only unit-test overrides were thread-scoped.
### What’s changed
* Removed `[ThreadStatic]` from:
```csharp
private static volatile IScheduler? _mainThreadScheduler;
private static volatile IScheduler? _taskpoolScheduler;
```
* Retained the existing `lock`-based lazy init to ensure thread-safe,
single-instance initialization:
* `MainThreadScheduler` defaults to `DefaultScheduler.Instance`.
* `TaskpoolScheduler` defaults to `TaskPoolScheduler.Default` (or
`DefaultScheduler.Instance` in `PORTABLE`).
* No public API changes.
### Current behavior (before this PR)
* `RxSchedulers.MainThreadScheduler` / `TaskpoolScheduler` are
**thread-local**: each thread can see an independent value, and new
threads may “re-initialize” to default unexpectedly.
* Tests or apps that set the scheduler on one thread can observe a
**different scheduler** on other threads.
### New behavior (after this PR)
* `RxSchedulers.MainThreadScheduler` / `TaskpoolScheduler` are
**process-wide singletons**:
* Set once, visible consistently across all threads.
* No unexpected resets when code runs on a different thread.
* `RxApp` semantics remain unchanged:
* Unit test overrides are still isolated via thread-static fields
**inside `RxApp` only**, preserving historical test behavior.
### Risks / Breaking changes
* Very low. The change restores the pre-split behavior and aligns
`RxSchedulers` with developer expectations (global, stable schedulers in
production code).
* Code that **relied** (intentionally or accidentally) on the
thread-local behavior of `RxSchedulers` may observe different (correct)
behavior now; this is considered a bug fix.
### How I verified
* Manual sanity checks:
* Set `RxSchedulers.MainThreadScheduler` on a background thread; read
from UI/main thread → **same instance**.
* Spawn multiple threads reading/writing schedulers concurrently →
stable value, no races (protected by `lock`).
* Ensured `RxApp` unit-test behavior remains intact (thread-static kept
where it was originally: `_unitTest*` fields).
### Repro (old bug)
```csharp
// On thread A
RxSchedulers.MainThreadScheduler = new TestScheduler();
// On thread B
var s = RxSchedulers.MainThreadScheduler; // Before: could be DefaultScheduler (reset). After: TestScheduler.
```
### Documentation impact
* None for public API. Internal behavior now matches historical RxUI
expectations:
* Use `RxSchedulers` for simple, app-global schedulers.
* Use `RxApp` when you need test-runner detection and per-thread unit
test overrides.
### Related
* Regression was introduced when splitting schedulers into
`RxSchedulers`: production fields gained `[ThreadStatic]`, diverging
from the original `RxApp` pattern where only **unit test** fields were
thread-static.
### Checklist
* [x] Bug fix (no breaking public API changes)
* [x] Behavior aligned with pre-split `RxApp`
* [ ] Tests added:1 parent 61cfabc commit c3d6d99Copy full SHA for c3d6d99
File tree
Expand file treeCollapse file tree
1 file changed
+0
-2
lines changedOpen diff view settings
Filter options
- src/ReactiveUI
Expand file treeCollapse file tree
1 file changed
+0
-2
lines changedOpen diff view settings
Collapse file
src/ReactiveUI/RxSchedulers.cs
Copy file name to clipboardExpand all lines: src/ReactiveUI/RxSchedulers.cs-2Lines changed: 0 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | 24 | | |
26 | 25 | | |
27 | | - | |
28 | 26 | | |
29 | 27 | | |
30 | 28 | | |
| |||
0 commit comments