# Running two threads in a strict interleaved order

**URL:** <https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931>\
**Category:** Using Swift\
**Tags:** thread\
**Created:** [March 27, 2024, 5:43am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931 "2024-03-27T05:43:15Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [March 27, 2024, 5:43am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/1 "2024-03-27T05:43:15Z")

</div>

I want to run the two threads in a strict interleave order: 1st, 2nd, 1st, 2nd, ...

Below works:

```swift
let mutex = NSLock()
var isFirst: Bool = true

Thread {
    while true {
        while !(mutex.withLock { isFirst }) {
            // busy waiting
        }
        print("first")
        mutex.withLock {
            isFirst = false
        }
    }
}.start()

Thread {
    while true {
        while (mutex.withLock { isFirst }) {
            // busy waiting
        }
        print("second")
        mutex.withLock {
            isFirst = true
        }
    }
}.start()

RunLoop.current.run(until: .distantFuture)

```

but is obviously bad because of the busy waiting.  
Tried to use a cond variable and a semaphore, but the result is neither correct nor concise nor Swifty.

How to do this better?

---

<div class="post-metadata">

**Author:** ![hgraves](https://avatars.discourse-cdn.com/v4/letter/h/ec9cab/32.png) [@hgraves](https://forums.swift.org/u/hgraves)\
**Post date:** [March 27, 2024, 5:59am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/2 "2024-03-27T05:59:26Z")

</div>

> [@tera](#):
>
> `DispatchQueue.main.sync`

It pushes to the main queue but queues are not threads so what is the intention of pushing to the main queue?

Edit: oh it looks like main queue always runs on main thread

Anyways, a good helper func I’ve seen in the past for something like this looked something like:

```swift
func block(complete: () -> Void) {
// only main thread can run completion handler
     if thread.current.isMainThread { 
                  complete()
          } else { block(complete) }
}

```

Maybe combined with someth like

```swift
func start() {

let sema DispatchSemaphore(value:0)

DispatchQueue.global().async({ 
 //only main thread can signal
block({(sema.signal())})
})

while true {
if sema.wait(timeout: .now().advancedBy(.0001)) == .timedOut { continue } 
break //only not the main thread can do this
}
// figure out what thread broke out and repeat
}
```

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [March 27, 2024, 6:07am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/3 "2024-03-27T06:07:23Z")

</div>

What are you actually trying to do? Do they have to be separate threads?

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [March 27, 2024, 2:22pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/4 "2024-03-27T14:22:43Z")

</div>

Yes, either two separate threads or two different dispatch queues, executing in the interlocked manner.

Please ignore `DispatchQueue.main.sync` above (it is there for something else). Commented out those `DispatchQueue.main.sync` in the code above to make it less confusing.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [March 27, 2024, 2:26pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/5 "2024-03-27T14:26:12Z")

</div>

I ask because the simplest answer I can think of is to have _one_ thread that pulls work items from two (threadsafe, non-Dispatch) queues alternately, rather than doing a cross-thread handshake. How applicable this is depends on what you’re actually trying to do.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [March 27, 2024, 2:30pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/6 "2024-03-27T14:30:30Z")

</div>

No, as I said it must be either two separate threads or two different dispatch queues. They will somehow "ping-pong the beachball of control" from one to another (mutex? semaphore?)

* * *

Having said that... If there's a magic solution that could make it work in a single thread mode I'd like to know that! Pseudocode:

```swift
func first() {
    // does something long
    // calls to "yieldToSecond()" every now and then
}

func second() {
    // does something long
    // calls to "yieldToFirst()" every now and then
}

```

---

<div class="post-metadata">

**Author:** ![nikolai.ruhe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nikolai.ruhe/32/23230_2.png) [@nikolai.ruhe](https://forums.swift.org/u/nikolai.ruhe)\
**Post date:** [March 27, 2024, 2:41pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/7 "2024-03-27T14:41:08Z")

</div>

Your setup describes two threads performing cooperative multitasking. When multiple threads have to communicate with each other, a condition lock might be the best synchronization idiom:

```swift
let lock = NSConditionLock(condition: 1)

Thread {
    while true {
        lock.lock(whenCondition: 1)
        print("first")
        lock.unlock(withCondition: 2)
    }
}.start()

Thread {
    while true {
        lock.lock(whenCondition: 2)
        print("second")
        lock.unlock(withCondition: 1)
    }
}.start()

```

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [March 27, 2024, 3:41pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/8 "2024-03-27T15:41:25Z")

</div>

> [@nikolai.ruhe](#):
>
> `NSConditionLock`

This works well, thank you!

---

<div class="post-metadata">

**Author:** ![hgraves](https://avatars.discourse-cdn.com/v4/letter/h/ec9cab/32.png) [@hgraves](https://forums.swift.org/u/hgraves)\
**Post date:** [March 27, 2024, 11:17pm UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/9 "2024-03-27T23:17:10Z")

</div>

Posting an amendment to this:

> func block(complete: () -\> Void) {  
> // only main thread can run completion handler  
> if thread.current.isMainThread {  
> complete()  
> } else { block(complete) }  
> }

```swift
func block<T>(_ block: @escaping (() -> T)) -> T {
     if Thread.isMainThread { return block() } 
      else { return DispatchQueue.main.sync { block() }

}

```

So it goes like:  
If on main thread run completion handler  
Otherwise return the completion handler on the main thread

Now assuming we start not on the main thread, we could write the name of the thread we are on and then loop and check if we are on it

---

<div class="post-metadata">

**Author:** ![ibex](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ibex/32/30439_2.png) [@ibex](https://forums.swift.org/u/ibex)\
**Post date:** [March 28, 2024, 1:12am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/10 "2024-03-28T01:12:42Z")

</div>

> [@tera](#):
>
> > [@nikolai.ruhe](#):
> >
> > `NSConditionLock`
> 
> This works well, thank you!

Yes, thank you!

> **Code for Review**
>
> ```swift
> //
> // InterleavedThreads.swift
> // CmdLine
> //
> // Created by ibex on 28/3/2024.
> //
> 
> // [https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/7]
> 
> import Foundation
> 
> @main
> class InterleavedThreads {
> let id: String
> let c1: Int
> let c2: Int
> let limit: Int
> var counter = 0
> 
> required init (id:String, c1:Int, c2:Int, limit:Int) {
> self.id = id
> self.c1 = c1
> self.c2 = c2
> self.limit = limit
> }
>     
> static func main () {
> let _1 = Self (id: "1", c1: 16, c2: 17, limit:32)
> let _2 = Self (id: "2", c1: 32, c2: 33, limit:64)
> 
> _1.run ()
> _2.run ()
> RunLoop.current.run (until: .distantFuture)
> }
>     
> private func run () {
> let lock = NSConditionLock (condition: c1)
> 
> Thread {
> while true {
> lock.lock(whenCondition: self.c1)
> defer {
> lock.unlock(withCondition: self.c2)
> }
>                 
> self.first ()
> if self.counter >= self.limit {
> return
> }
> 
> }
> }.start()
> 
> Thread {
> while true {
> lock.lock(whenCondition: self.c2)
> defer {
> lock.unlock(withCondition: self.c1)
> }
>                 
> self.second ()
> if self.counter >= self.limit {
> return
> }
> 
> }
> }.start()
> }
>     
> private func first () {
> print (#function, id, c1, c2, counter)
> counter += 1
> }
>     
> private func second () {
> print (#function, id, c1, c2, counter)
> counter += 1
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [April 1, 2024, 3:05am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/11 "2024-04-01T03:05:20Z")

</div>

I implemented the code in terms of "yield", although the API of this yield is a bit weird:

- yield takes two parameters: the current thread identification and the other thread identification
- the other thread identification parameter is optional and when called first time from a thread the thread has to pass nil there.

Don't see now how to make this API less awkward.

Full test code:

```swift
let lock = NSConditionLock(condition: 0)
var progress = 0

func yield(from: Int, to: Int?) {
    if let to {
        lock.unlock(withCondition: to)
    }
    lock.lock(whenCondition: from)
}

Thread {
    var other: Int?
    while true {
        yield(from: 0, to: other)
        other = 1
        printProgress()
    }
}.start()

Thread {
    var other: Int?
    while true {
        yield(from: 1, to: other)
        other = 0
        printProgress()
    }
}.start()

func printProgress() {
    progress += 1
    if (progress % 1000000) == 0 {
        print(progress)
    }
}

RunLoop.current.run(until: .distantFuture)

```

Note that `printProgress` uses a global `progress` variable without the need of synchronising (via lock or atomic or otherwise) – this is safe because the two threads are run in a serialised manner.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [April 1, 2024, 4:11am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/12 "2024-04-01T04:11:46Z")

</div>

> [@tera](#):
>
> this is safe because the two threads are run in a serialised manner

This is not generally sufficient! Different threads may run on different cores, which have different caches, that can get out of sync. You will generally only see this on arm architectures, which provide weaker memory guarantees than x86. In this case, however, you have effectively protected the progress variable with the same lock you’re using as a condition, so it works out.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [April 1, 2024, 5:19am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/13 "2024-04-01T05:19:10Z")

</div>

Good catch. I wonder what changes could I make to this implementation to see the effect you are talking about.

---

<div class="post-metadata">

**Author:** ![ksluder](https://avatars.discourse-cdn.com/v4/letter/k/eada6e/32.png) [@ksluder](https://forums.swift.org/u/ksluder)\
**Post date:** [April 1, 2024, 6:09am UTC](https://forums.swift.org/t/running-two-threads-in-a-strict-interleaved-order/70931/14 "2024-04-01T06:09:51Z")

</div>

I’m not sure you can. Pretty much all synchronization primitives will issue a full memory barrier.

Edit: actually, I take that back. Apparently it’s idiomatic to issue a barrier only in the _inner_ synchronization domain (”same CPU cluster”, roughly speaking), not the full system.
