Skip to content

mattmassicotte/TaskGate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Platforms Matrix

TaskGate

An tool for managing actor reentrancy.

This package exposes two types: AsyncGate and AsyncRecursiveGate. These allow you to define asynchronous critical sections. Only one task can enter a critical section at a time. Unlike a traditional lock, you can safely make async calls while these gates are held.

The intended use-case for these is managing actor reentrancy.

Some other concurrency packages you might find useful are Queue and Semaphore. Gate is an independent, but extremely similar package.

Integration

Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/mattmassicotte/TaskGate", branch: "main")
]

Usage

Gates are very intentionally non-Sendable. The purpose of a gate is to control tasks running concurrently within a single actor, and making them non-Sendable allows the compiler will help enforce that concept.

Note that trying to acquire an already-gated AsyncGate will deadlock your actor.

import TaskGate

actor MyActor {
  var value = 42
  let gate = AsyncGate()
  let recursiveGate = AsyncRecursiveGate()

  func hasCriticalSections() async {
    // no matter how many tasks call this method,
    // only one will be able to execute at a time
	await gate.withGate {
      self.value = await otherObject.getValue()
    }
  }

  func hasCriticalSectionsBlock() async {
    await recursiveGate.withGate {
      // acquiring this multiple times within the same task is safe
      await recursiveGate.withGate {
        self.value = await otherObject.getValue()
      }
    }
  }
}

Both of these gate types support priority escalation propagation to help avoid priority inversions. However, the API required to do this was introduced with SE-0462, which is only available in the 26 OSes and later.

It is important to note that gates cannot be used from a non-async context. Actually doing this would require some trickery, as they both only have async interfaces. But, if you find a way, perhaps via ObjC bridging, you should expect a crash.

Contributing and Collaboration

I would love to hear from you! Issues or pull requests work great. Both a Matrix space and Discord are also available for live help, but I have a strong bias towards answering in the form of documentation.

I prefer collaboration, and would love to find ways to work together if you have a similar project.

I prefer indentation with tabs for improved accessibility. But, I'd rather you use the system you want and make a PR than hesitate because of whitespace.

By participating in this project you agree to abide by the Contributor Code of Conduct.

About

An tool for managing actor reentrancy with Swift Concurrency

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors

Languages