Skip to main content

Concurrency 101


Race Condition

Race condition (or data race) is an unwanted condition that can happen during the program execution. When a shared resource is being accessed from multiple threads at the same time, multiple read/write instructions could potentially lead to various hard-to-resolve issues. These "race" issues are either inaccurate data (getting old value if read instruction came before newest write, or vice versa, multiple writes from different threads could lead to incorrect value), or corrupt memory, which could often cause a crash. It is the most common problem in the multi-threading programming, and produces some of the hardest issues to detect and solve. It's important to know that the race condition is non-deterministic, which means it won't happen everytime, which can make debugging very hard.

Critical Section

Critical section is the location in the code base that contains the shared resource being accessed from multiple places. Various mechanisms are required to serialize critical sections in the codebase to avoid race conditions or crashes. In iOS, one of the mechanisms to protect the critical section is using locks to lock/unlock on each read/write access, or by dispatching instructions on a serial queue.

Priority Inversion

Priority Inversion in concurrent programming is a situation when a high priority (usually user-interactive) task is waiting for some low priority or a big time-consuming task to finish first. This issue could lead to slow or unresponsive program (or app).

Deadlock

Deadlock is a situation when two programs accessing the same shared resource are preventing each other access to that resource, resulting in an endless halt. In iOS, the easiest way to create a dead lock is by using serial queue, and by dispatching a sync block inside another sync or async block. Other block cannot finish until the sync block starts, and sync block cannot start until outer block finishes because of the serial execution.
let queue = DispatchQueue(label: "label")
queue.async {
    queue.sync {
        // outer block is waiting for this inner block to complete,
        // inner block won't start before outer block finishes
        // => deadlock
    }
    // this will never be reached
}

Comments