Skip to content

Commit 59f911f

Browse files
docs: enhance MonoTask.swift comments (thread-safety, API notes) and update ModuleReadingList checklist; remove force unwraps in callback registration
1 parent bb1b6aa commit 59f911f

2 files changed

Lines changed: 22 additions & 12 deletions

File tree

ModuleReadingList.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Goal: Enhance comments across all Swift files in `Sources` using clear, consiste
4444

4545
## Comment Enhancement Checklist (Sources)
4646

47-
- [ ] `Sources/Monstask/MonoTask.swift`
47+
- [x] `Sources/Monstask/MonoTask.swift`
4848
- [ ] `Sources/Monstask/KVLightTasksManager.swift`
4949
- [ ] `Sources/Monstask/KVHeavyTasksManager.swift`
5050
- [ ] `Sources/Monstore/MemoryCache/MemoryCache.swift`

Sources/Monstask/MonoTask.swift

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,8 @@ import Combine
5757
/// ```
5858
///
5959
/// ## Thread Safety:
60-
/// MonoTask uses two semaphores for fine-grained thread safety:
61-
/// - `resultSemaphore`: Protects cached result and expiration state
62-
/// - `callbackSemaphore`: Protects callback array and execution state
60+
/// MonoTask uses a single internal semaphore for fine-grained thread safety:
61+
/// - Protects cached result, expiration timestamp, callback registration, and execution state
6362
///
6463
/// ## Performance:
6564
/// - **Execution Merging**: Prevents duplicate work when multiple callers request same task
@@ -150,10 +149,10 @@ public class MonoTask<TaskResult> {
150149
/// 2. Determines if a new execution should be started (execution merging)
151150
/// 3. Starts execution only if no other execution is currently running
152151
///
153-
/// **Thread Safety**: Protected by `callbackSemaphore`
152+
/// **Thread Safety**: Protected by a single internal semaphore
154153
///
155154
/// **Execution Merging**: Multiple concurrent calls to this method will:
156-
/// - All register their callbacks in the `_callbacks` array
155+
/// - All register their callbacks in the `waitingCallbacks` array
157156
/// - Only the first call will trigger actual execution
158157
/// - All callbacks receive the same result when execution completes
159158
///
@@ -171,7 +170,7 @@ public class MonoTask<TaskResult> {
171170

172171
// 2) Register callback for result notification
173172
if let completionCallback {
174-
waitingCallbacks!.append(completionCallback)
173+
waitingCallbacks?.append(completionCallback)
175174
}
176175

177176
// 3) Schedule a brand-new execution and mark force scheduled
@@ -204,7 +203,7 @@ public class MonoTask<TaskResult> {
204203

205204
// Register callback for result notification
206205
if let completionCallback {
207-
waitingCallbacks!.append(completionCallback)
206+
waitingCallbacks?.append(completionCallback)
208207
}
209208

210209
// Start execution only if not already running (execution merging)
@@ -228,8 +227,8 @@ public class MonoTask<TaskResult> {
228227
/// - If `clearResult()` is called during execution, execution ID changes
229228
/// - Stale retry attempts check their ID and abort if execution was cancelled
230229
///
231-
/// **Thread Safety**: This method runs on `taskQueue` and uses `resultSemaphore`
232-
/// for cache state protection
230+
/// **Thread Safety**: This method runs on `taskQueue` and uses the internal semaphore
231+
/// for cache and execution state protection
233232
///
234233
/// - Parameter retryConfiguration: Current retry configuration (decrements on each retry)
235234
private func _unsafe_execute(retry retryConfiguration: RetryCount) {
@@ -283,8 +282,8 @@ public class MonoTask<TaskResult> {
283282
/// 3. Invoke all callbacks with the same result
284283
/// 4. Transition task from "executing" to "idle" state
285284
///
286-
/// **Thread Safety**: Uses `callbackQueue` and `callbackSemaphore` for safe
287-
/// callback array manipulation
285+
/// **Thread Safety**: Uses `callbackQueue` for delivery. Callback extraction and state
286+
/// transitions are protected by the internal semaphore before hopping to `callbackQueue`.
288287
///
289288
/// **State Transition**: After this method completes, the task transitions from
290289
/// "executing" to "idle" state (`waitingCallbacks` becomes nil)
@@ -304,7 +303,18 @@ public class MonoTask<TaskResult> {
304303
}
305304
}
306305

306+
/// Latest successfully cached result if available and not expired.
307+
///
308+
/// - Note: This property is `@Published` for Combine subscribers and updated on
309+
/// the internal synchronization boundary. Delivery occurs on `callbackQueue` when
310+
/// produced by an execution.
307311
@Published public private(set) var result: TaskResult? = nil
312+
313+
/// Indicates whether the task is currently executing.
314+
///
315+
/// - Note: This property is `@Published` and flips to `true` when the first caller
316+
/// begins an execution (i.e., `waitingCallbacks` becomes non-nil) and back to `false`
317+
/// when callbacks have been notified and `waitingCallbacks` is cleared.
308318
@Published public private(set) var isExecuting: Bool = false
309319
}
310320

0 commit comments

Comments
 (0)