{"id":928,"url":"https://github.com/typelift/Concurrent","last_synced_at":"2025-07-30T19:33:03.641Z","repository":{"id":20993257,"uuid":"24282811","full_name":"typelift/Concurrent","owner":"typelift","description":"Functional Concurrency Primitives","archived":false,"fork":false,"pushed_at":"2019-10-05T15:15:30.000Z","size":308,"stargazers_count":209,"open_issues_count":5,"forks_count":20,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-11-28T17:11:54.480Z","etag":null,"topics":["concurrency","lock","software-transactional-memory","synchronization"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typelift.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-21T05:13:44.000Z","updated_at":"2024-07-03T17:55:54.000Z","dependencies_parsed_at":"2022-07-31T05:17:59.049Z","dependency_job_id":null,"html_url":"https://github.com/typelift/Concurrent","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FConcurrent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FConcurrent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FConcurrent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelift%2FConcurrent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelift","download_url":"https://codeload.github.com/typelift/Concurrent/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228179028,"owners_count":17881125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["concurrency","lock","software-transactional-memory","synchronization"],"created_at":"2024-01-05T20:15:34.837Z","updated_at":"2024-12-04T19:32:24.229Z","avatar_url":"https://github.com/typelift.png","language":"Swift","readme":" [![Build Status](https://travis-ci.org/typelift/Concurrent.svg?branch=master)](https://travis-ci.org/typelift/Concurrent)\n\nConcurrent\n==========\n\nConcurrent is a collection of functional concurrency primitives inspired by\n[Concurrent ML](http://cml.cs.uchicago.edu/) and [Concurrent\nHaskell](http://hackage.haskell.org/package/base-4.7.0.2/docs/Control-Concurrent.html).\nTraditional approaches to concurrency like locks, latches, and semaphores all\nfall under the same category of basic resource protection.  While this affords\nthem a large measure of simplicity, their use is entirely ad-hoc, and failing to\nproperly lock or unlock critical sections can lead a program to beachball or\nworse.  In addition, though we have become accustomed to performing work on\nbackground threads, communication between these threads is frought with peril.  \n\nThe primitives in this library instead focus on *merging* data with protection,\nchoosing to abstract away the use of locks entirely.  By approaching concurrency\nfrom the data side, rather than the code side, thread-safety, synchronization,\nand protection become inherent in types rather than in code.\n\nTake this simple example:\n\n```swift\nimport struct Concurrent.Chan\n\n/// A Channel is an unbounded FIFO stream of values with special semantics\n/// for reads and writes.\nlet chan = Chan\u003cInt\u003e()\n\n/// All writes to the Channel always succeed.  The Channel now contains `1`.\nchan.write(1) // happens immediately\n\n/// Reads to non-empty Channels occur immediately.  The Channel is now empty.\nlet x1 = chan.read()\n\n/// But if we read from an empty Channel the read blocks until we write to the Channel again.\nDispatchQueue.global().asyncAfter(deadline: .now() + .seconds(1)) {\n  chan.write(2) // Causes the read to suceed and unblocks the reading thread.\n}\n\nlet x2 = chan.read() // Blocks until the dispatch block is executed and the Channel becomes non-empty.\n```\n\nUnlike lock-based protection mechanisms, we can wrap mutable variables that must\nbe accessed concurrently in an MVar.\n\n```swift\nimport class Concurrent.MVar\n\n/// An MVar (Mutable Variable) is a thread-safe synchronizing variable that can be used for\n/// communication between threads.\n///\n/// This MVar is currently empty.  Any reads or writes to it will block until it becomes \"full\".\nlet counter : MVar\u003cInt\u003e = MVar()\n\n/// Attempt to increment the counter from 3 different threads.  Because the counter is empty,\n/// all of these writes will block until a value is put into the MVar.\nDispatchQueue.global().async {\n  counter.modify_ { $0 + 1 }\n  print(\"Modifier #1\")\n}\nDispatchQueue.global().async {\n  counter.modify_ { $0 + 1 }\n  print(\"Modifier #2\")\n}\nDispatchQueue.global().async {\n  counter.modify_ { $0 + 1 }\n  print(\"Modifier #3\")\n}\n\n/// All the writes will now proceed and unblock each thread in turn.  The order of writes\n/// is determined by the order in which each thread called `modify(_ :)`.\ncounter.put(0)\n\n// \u003e \"Modifier #1\"\n// \u003e \"Modifier #3\"\n// \u003e \"Modifier #2\"\n\n/// Empties the MVar.  If we just wanted the value without emptying it, we would use\n/// `read()` instead.\n///\n/// Because our take occured after the put, all of the modifications we made before will\n/// complete before we read the final value.\nprint(counter.take()) // 3\n```\n\n`MVar`s can also be used purely as a synchronization point between multiple threads:\n\n```swift\nimport class Concurrent.MVar\n\nlet pingvar : MVar\u003cString\u003e = MVar()\nlet pongvar : MVar\u003cString\u003e = MVar()\nlet done = MVar\u003c()\u003e() // The synchronization point\n\n/// Puts a value into the now-empty ping variable then blocks waiting for the\n/// pong variable to have a value put into it.  Once we have read the pong variable,\n/// we unblock the done MVar, and in doing so, unblock the main thread.\nDispatchQueue.global().async {\n  pingvar.put(\"ping\")\n  _ = pongvar.take()\n  done.put(())\n}\n\n/// Takes the contents of the ping variable then puts a value into the pong variable\n/// to unblock the take we just performed.\nDispatchQueue.global().async {\n  _ = pingvar.take()\n  pongvar.put(\"pong\")\n}\n\n/// Blocks until all work has completed.\ndone.take()\n```\n\nConcurrent also exposes a structure for [Software Transactional\nMemory](https://en.wikipedia.org/wiki/Software_transactional_memory) for\nsafe and structured access to shared memory:\n\n```swift\ntypealias Account = TVar\u003cUInt\u003e\n\n/// Some atomic operations\nfunc withdraw(from account : Account, amount : UInt) -\u003e STM\u003c()\u003e { \n  return account.read().flatMap { balance in\n    if balance \u003e amount {\n      return account.write(balance - amount)\n    }\n    throw TransactionError.insufficientFunds\n  } \n}\n\nfunc deposit(into account : Account, amount : UInt) -\u003e STM\u003c()\u003e { \n  return account.read().flatMap { balance in\n    return account.write(balance + amount)\n  }\n}\n\nfunc transfer(from : Account, to : Account, amount : UInt) -\u003e STM\u003c()\u003e { \n  return from.read().flatMap { fromBalance in\n    if fromBalance \u003e amount {\n      return withdraw(from: from, amount: amount)\n          .then(deposit(into: to, amount: amount))\n    }\n    throw TransactionError.insufficientFunds\n  }\n}\n\n/// Here are some bank accounts represented as TVars - transactional memory\n/// variables.\nlet alice = Account(200)\nlet bob = Account(100)\n\n/// All account activity that will be applied in one contiguous transaction.\n/// Either all of the effects of this transaction apply to the accounts or\n/// everything is completely rolled back and it was as if nothing ever happened.\nlet finalStatement = \n    transfer(from: alice, to: bob, amount: 100)\n        .then(transfer(from: bob, to: alice, amount: 20))\n        .then(deposit(into: bob, amount: 1000))\n        .then(transfer(from: bob, to: alice, amount: 500))\n        .atomically()\n```\n\nSystem Requirements\n===================\n\nConcurrent supports OS X 10.9+ and iOS 7.0+.\n\nInstallation\n=====\n\n#### Swift Package Manager\n\n- Add Concurrent to your `Package.swift` file's dependencies section:\n\n```\n.package(url: \"https://github.com/typelift/Concurrent.git\", \"0.4.0\"..\u003c\"1.0.0\")\n```\n\n#### Carthage\nCreate a `Cartfile` that lists the framework and run `carthage bootstrap`. Follow the [instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios) to add `$(SRCROOT)/Carthage/Build/iOS/Concurrent.framework` to an iOS project.\n\n```\ngithub \"typelift/Concurrent\"\n```\n\n#### Manually\n1. Download and drop `/Sources` folder in your project.  \n2. Congratulations!  \n\n#### Framework\n\n- Drag Concurrent.xcodeproj or Concurrent-iOS.xcodeproj into your project tree as a subproject\n- Under your project's Build Phases, expand Target Dependencies\n- Click the + and add Concurrent\n- Expand the Link Binary With Libraries phase\n- Click the + and add Concurrent\n- Click the + at the top left corner to add a Copy Files build phase\n- Set the directory to Frameworks\n- Click the + and add Concurrent\n\nLicense\n=======\n\nConcurrent is released under the MIT license.\n\n","funding_links":[],"categories":["Concurrency","Libraries","Swift"],"sub_categories":["Linter","[Swift](https://developer.apple.com/swift)","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelift%2FConcurrent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelift%2FConcurrent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelift%2FConcurrent/lists"}