# How @MainActor works

DevFeed: [How @MainActor works](<https://devfeed.tech/articles/how-mainactor-works-21713.md>)

Original publisher: [Read original article](<https://oleb.net/2022/how-mainactor-works/>)

Author: Ole Begemann

Published: 2022-05-05T13:52:42Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Protocol (disambiguation)](<https://devfeed.tech/topics/protocol.md>)

Tags: [await](<https://devfeed.tech/tags/await.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [executor](<https://devfeed.tech/tags/executor.md>), [main-thread](<https://devfeed.tech/tags/main-thread.md>), [protocol](<https://devfeed.tech/tags/protocol.md>), [swift](<https://devfeed.tech/tags/swift.md>)

## AI overview

This tutorial explains how Swift's @MainActor works by reimplementing it in simplified form. It describes the roles of global actors and custom executors, including how a custom serial executor can run jobs on the main dispatch queue.

## Source excerpt

@MainActor is a Swift annotation to coerce a function to always run on the main thread and to enable the compiler to verify this. How does this work? In this article, I'm going to reimplement @MainActor in a slightly simplified form for illustration purposes, mainly to show how little "magic" there is to it. The code of the real implementation in the Swift standard library is available in the Swift repository. @MainActor relies on two Swift features, one of them unofficial: global actors and custom executors. Global actors MainActor is a global actor. That is, it provides a single actor instance that is shared between all places in the code that are annotated with @MainActor. All global actors must implement the shared property that's defined in the GlobalActor protocol (every global actor implicitly conforms to this protocol): @globalActor final actor MyMainActor { // Requirements from the implicit GlobalActor conformance typealias ActorType = MyMainActor static var shared: ActorType = MyMainActor() // Don't allow others to create instances private init() {} } At this point, we have a global actor that has the same semantics as any other actor. That is, functions annotated with @MyMainActor will run on a thread in the cooperative thread pool managed by the Swift runtime. To move the work to the main thread, we need another concept, custom executors. Executors A bit of terminology: The compiler splits async code into jobs. A job roughly corresponds to the code from one await (= potential suspension point) to the next. The runtime submits each job to an executor. The executor is the object that decides in which order and in which context (i.e. which thread or dispatch queue) to run the jobs. Swift ships with two built-in executors: the default concurrent executor, used for "normal", non-actor-isolated async functions, and a default serial executor. Every actor instance has its own instance of this default serial executor and runs its code on it. Since the serial exec