Sheshnath
Sheshnath

Reputation: 3393

How to make thread safe code block in swift

I tried multiple solution/answers given on stackoverflow but none of them worked for me. Some of them is as below :

https://stackoverflow.com/a/30495424/3145189

Is this safe to call wait() of DispatchSemaphore several times at one time?

https://stackoverflow.com/a/37155631/3145189

I am trying to achieve very simple thing, code block or function should execute serially, regardless of from which thread it's been called.

My Example code :

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

   DispatchQueue.global().async {
        self.testLog(name:"first")
    }
    DispatchQueue.global().async {
        self.testLog(name:"second")
    }

    DispatchQueue.main.async {
        self.testLog(name: "mainthread")
    }
}


func testLog(name:String) -> Void {
        for i in 1..<1000 {
            print("thread test \(i) name =\(name)")
        }

    }

So output should be like -

first thread call

thread test 1 name =first

thread test 2 name =first

thread test 3 name =first

.

.

.

thread test 999 name =first

second thread call

thread test 1 name =second

thread test 2 name =second

.

.

.

thread test 999 name =second

main thread call

thread test 1 name =mainthread

thread test 2 name =mainthread

.

.

.

thread test 999 name =mainthread

If function is called on first thread, it should continue print log for the first thread only. Order of thread can vary I don't care means even if it's print mainthread log first then second and first doesn't matter logs should be grouped.

Upvotes: 1

Views: 3462

Answers (2)

CRD
CRD

Reputation: 53000

I am trying to achieve very simple thing, code block or function should execute serially, regardless of from which thread it's been called.

To execute serially you use a Dispatch serial queue. If you were writing a class or struct you could use a static let at class/struct level to store your queue in which your serialising function could dispatch to. A static let in this case is equivalent to a "class variable" in some languages.

If you were writing in (Objective-)C such variables can also be declared at the function level, that is a variable with global lifetime but with scope limited to within the function. Swift does not support these within a function, but you can scope a struct to a function...

func testLog(name:String) -> Void
{
   struct LocalStatics
   {
      static let privateQueue = DispatchQueue(label: "testLogQueue")
   }

   // run the function body on the serial queue - could use async here
   // and the body would still run not interleaved with other calls but
   // the caller need not wait for it to do so 
   LocalStatics.privateQueue.sync {
      for i in 1..<1000
      {
         print("thread test \(i) name =\(name)")
      }
   }
}

(For a debate on "local statics" in Swift see this SO Q&A)

Upvotes: 0

Aris
Aris

Reputation: 1559

This will execute the calls serially. Keep a reference to serialQueue and you can submit blocks from any thread.

let serialQueue = DispatchQueue(label: "serial_queue")

    serialQueue.async {
        self.testLog(name: "first")
    }
    serialQueue.async {
        self.testLog(name: "second")
    }

    serialQueue.async {
        self.testLog(name: "third")
    }

Upvotes: 3

Related Questions