{"id":25082208,"url":"https://github.com/niksativa/threading","last_synced_at":"2026-04-02T17:59:36.003Z","repository":{"id":46052299,"uuid":"360091014","full_name":"NikSativa/Threading","owner":"NikSativa","description":"Thread-safe concurrency utilities for Swift: mutexes, locks, and dispatch queue abstractions","archived":false,"fork":false,"pushed_at":"2026-03-28T14:17:58.000Z","size":93,"stargazers_count":0,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T16:40:31.572Z","etag":null,"topics":["atomic","concurrency","dispatchqueue","ios","locking","macos","mutex","propertywrapper","swift","swiftpm","synchronization","thread","threadsafe","tvos","visionos","watchos"],"latest_commit_sha":null,"homepage":"https://swiftpackageindex.com/NikSativa/Threading","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NikSativa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-04-21T08:32:44.000Z","updated_at":"2026-03-28T14:10:23.000Z","dependencies_parsed_at":"2025-12-12T00:12:20.175Z","dependency_job_id":null,"html_url":"https://github.com/NikSativa/Threading","commit_stats":{"total_commits":36,"total_committers":4,"mean_commits":9.0,"dds":"0.13888888888888884","last_synced_commit":"969bd1a563eacac79f6ef719b8fc1f0bb5a31bfd"},"previous_names":["niksativa/threading","niksativa/nqueue"],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/NikSativa/Threading","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FThreading","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FThreading/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FThreading/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FThreading/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NikSativa","download_url":"https://codeload.github.com/NikSativa/Threading/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikSativa%2FThreading/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312744,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atomic","concurrency","dispatchqueue","ios","locking","macos","mutex","propertywrapper","swift","swiftpm","synchronization","thread","threadsafe","tvos","visionos","watchos"],"created_at":"2025-02-07T05:29:06.952Z","updated_at":"2026-04-02T17:59:35.993Z","avatar_url":"https://github.com/NikSativa.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Threading\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FNikSativa%2FThreading%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/NikSativa/Threading)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FNikSativa%2FThreading%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/NikSativa/Threading)\n[![NikSativa CI](https://github.com/NikSativa/Threading/actions/workflows/swift_macos.yml/badge.svg)](https://github.com/NikSativa/Threading/actions/workflows/swift_macos.yml)\n[![License](https://img.shields.io/github/license/Iterable/swift-sdk)](https://opensource.org/licenses/MIT)\n\nThreading is a framework that provides type-safe abstractions for thread synchronization and concurrent programming in Swift. It offers a set of tools for working with locks, mutexes, and atomic operations, making concurrent code safer and easier to write.\n\n## Overview\n\nThreading provides several key components:\n\n- **Queue**: A type-safe wrapper around Grand Central Dispatch queues\n- **Mutexing**: A protocol for thread-safe value access\n- **Locking**: A protocol for basic synchronization primitives\n- **AtomicValue**: A property wrapper for thread-safe properties\n\n## Topics\n\n### Queue Management\n\n- ``Queue``: A type-safe wrapper for GCD queues; provides convenient access to system queues, custom queue creation, and safe main-thread access.\n- ``Queueable``: A protocol for queue-like types that exposes a common interface for queue operations.\n- ``DelayedQueue``: A queue with built-in delay support, ideal for throttling, rate limiting, and cancelable delayed operations.\n\n### Synchronization\n\n- ``Mutexing``: A protocol for synchronized access to values; supports blocking and non-blocking execution with error propagation. Supports `@dynamicCallable` and `@dynamicMemberLookup` for convenient syntax.\n- ``Locking``: A protocol for lock implementations, supporting core locking behaviors, including recursive locks. Supports `@dynamicCallable` for functional-style syntax.\n- ``AnyMutex``: A type-erased wrapper around any `Mutexing` implementation.\n- ``AnyLock``: A type-erased wrapper around any `Locking` implementation.\n\n### Mutex Implementations\n\n- ``SyncMutex``: A native mutex using the system synchronization framework (macOS 15.0+, iOS 18.0+); supports recursive locking and integrates with debugging tools.\n- ``OSAllocatedUnfairMutex``: A high-performance mutex using OS-allocated unfair locks (macOS 13.0+, iOS 16.0+).\n- ``QueueBarrier``: A mutex that uses dispatch queue barriers for synchronization; useful for queue-based concurrency patterns.\n- ``LockedValue``: A generic mutex-backed value container that allows custom locking strategies.\n\n### Property Wrappers\n\n- ``AtomicValue``: A property wrapper that synchronizes access to a property using a configurable mutex.\n\n### Concurrency Utilities\n\n- ``USendable``: A lightweight wrapper for non-Sendable types, useful when bridging legacy types into concurrency contexts. Requires manual thread safety.\n\n## Usage\n\n### Working with Queues\n\nPerform synchronous work on the main thread safely:\n\n```swift\nQueue.main.sync {\n    // Your task on main thread\n}\n```\n\nPerform asynchronous work:\n\n```swift\nQueue.main.async {\n    // Your task on main thread\n}\n```\n\nCreate custom queues with explicit parameters:\n\n```swift\nlet customQueue = Queue.custom(\n    label: \"com.example.queue\",\n    qos: .utility,\n    attributes: .serial\n)\n\ncustomQueue.async {\n    // Your work here\n}\n```\n\nUse `DelayedQueue` for delayed or conditional execution:\n\n```swift\n// Execute after a delay\nlet delayed = DelayedQueue.n.asyncAfter(deadline: .now() + 2, queue: .main)\ndelayed.fire {\n    print(\"Executed after 2 seconds\")\n}\n\n// Synchronous execution\nlet sync = DelayedQueue.n.sync(.main)\nsync.fire {\n    print(\"Executed synchronously\")\n}\n\n// Asynchronous execution\nlet async = DelayedQueue.n.async(.background)\nasync.fire {\n    print(\"Executed asynchronously\")\n}\n```\n\n### Thread-Safe Value Access\n\nUse mutexes to protect shared values:\n\n```swift\nlet counter = LockedValue(initialValue: 0)\n\n// Safely modify the value\ncounter.sync { value in\n    value += 1\n}\n\n// Get the current value\nlet currentValue = counter.sync { value in\n    return value\n}\n\n// Using dynamic callable syntax (functional style)\ncounter { $0 += 1 }\nlet doubled = counter { $0 * 2 }\n```\n\nUse `trySync` for non-blocking access:\n\n```swift\nif let value = counter.trySync({ $0 }) {\n    print(\"Current value: \\(value)\")\n}\n```\n\n### AtomicValue Properties\n\nUse the `@AtomicValue` property wrapper for thread-safe properties:\n\n```swift\n@AtomicValue var counter = 0\n\n// Using sync method\n$counter.sync { $0 += 1 }\n\n// Using dynamic callable syntax (functional style)\n$counter { $0 = 10 }\n\n// Direct property access (thread-safe)\ncounter = 5\nlet value = counter\n```\n\nYou can also specify a custom mutex type:\n\n```swift\n@AtomicValue(mutexing: SyncMutex.self) var counter = 0\n@AtomicValue(lock: .osAllocatedUnfair()) var highPerformance = 0\n```\n\n### Concurrency Workarounds\n\nWhen working with `@MainActor`-isolated APIs:\n\n```swift\nQueue.isolatedMain.sync {\n    // Access UI elements safely\n    view.backgroundColor = .red\n}\n```\n\n### Working with Non-Sendable Types\n\nThe `USendable` type provides a way to work with non-Sendable types in concurrent contexts. It's particularly useful when you need to:\n\n- Access UIKit/AppKit objects from concurrent contexts\n- Work with legacy code that hasn't been updated for Swift concurrency\n- Bridge between synchronous and asynchronous code\n\n\u003e [!WARNING]\n\u003e **Important:** `USendable` doesn't make the wrapped value thread-safe. It only marks the type as `@unchecked Sendable`. You must ensure thread safety through other means, such as:\n\u003e - Accessing the value only on the main thread\n\u003e - Using proper synchronization mechanisms\n\u003e - Following the value's thread-safety requirements\n\n```swift\n// Wrap a UIKit view\nlet unsafe = USendable(ImageView())\n\n// Access it safely on the main thread\nQueue.main.async {\n    let view = unsafe.value\n    view.backgroundColor = .red\n}\n\n// Or use it in a Task with proper synchronization\nTask { @MainActor in\n    let view = unsafe.value\n    view.backgroundColor = .blue\n}\n```\n\n## Advanced Features\n\n### Dynamic Callable Syntax\n\nBoth `Locking` and `Mutexing` protocols support `@dynamicCallable`, allowing functional-style syntax:\n\n```swift\n// Using Locking protocol\nlet lock: Locking = AnyLock.default\nlock {\n    // Critical section\n    performWork()\n}\n\n// Using Mutexing protocol\nlet counter = LockedValue(initialValue: 0)\ncounter { $0 += 1 }\nlet value = counter { $0 }\n\n// Using AtomicValue\n@AtomicValue var count = 0\n$count.sync { $0 += 1 }\n\n// Or using dynamic callable syntax (works for any type)\n$count { $0 += 1 }\n```\n\n### Dynamic Member Lookup\n\n`Mutexing` and `AtomicValue` support `@dynamicMemberLookup` for convenient property access:\n\n```swift\n@AtomicValue var user = User(name: \"Alice\", age: 30)\n\n// Thread-safe property access\nlet name = user.name  // Automatically synchronized\nuser.age = 31        // Thread-safe mutation\n```\n\n## Best Practices\n\n1. **Keep Critical Sections Short**\n   ```swift\n   // Good\n   counter.sync { value in\n       value += 1\n   }\n\n   // Avoid\n   counter.sync { value in\n       // Long-running operations block other threads\n       performExpensiveOperation()\n   }\n   ```\n\n2. **Choose Appropriate Mutex Type**\n   - Use `SyncMutex` for general-purpose synchronization (macOS 15.0+, iOS 18.0+)\n   - Use `OSAllocatedUnfairMutex` for high-performance scenarios (macOS 13.0+, iOS 16.0+)\n   - Use `QueueBarrier` when working with GCD queues\n   - Use `LockedValue` when you need custom lock behavior\n   - Use `AnyLock.default` (recursive pthread) as a safe default\n\n3. **Handle Errors Properly**\n   ```swift\n   do {\n       try mutex.sync { value in\n           try performRiskyOperation(value)\n       }\n   } catch {\n       // Handle error appropriately\n   }\n   ```\n\n4. **Use Try-Lock for Non-Blocking Operations**\n   ```swift\n   // Non-blocking access\n   if let result = lock.trySync({ computeValue() }) {\n       // Lock acquired, work completed\n   } else {\n       // Lock busy, handle accordingly\n   }\n   ```\n\n## Requirements\n\n- iOS 13.0+ / macOS 11.0+ / tvOS 13.0+ / watchOS 6.0+ / visionOS 1.0+\n- Swift 5.5+\n- Xcode 13.0+\n\n\u003e **Note:** Some features require newer platform versions:\n\u003e - `SyncMutex`: macOS 15.0+, iOS 18.0+, tvOS 18.0+, watchOS 11.0+, visionOS 2.0+\n\u003e - `OSAllocatedUnfairMutex` / `OSAllocatedUnfairLock`: macOS 13.0+, iOS 16.0+, tvOS 16.0+, watchOS 9.0+\n\n## Installation\n\n### Swift Package Manager\n\nAdd the following to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/NikSativa/Threading.git\", from: \"1.0.0\")\n]\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniksativa%2Fthreading","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniksativa%2Fthreading","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniksativa%2Fthreading/lists"}