Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of Semaphore.wait(timeout: .now())?

Looking at some Apple code sample, I found this:

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    // wait() is used to drop new notifications if old ones are still processing, to avoid queueing up a bunch of stale data.
    if metadataObjectsOverlayLayersDrawingSemaphore.wait(timeout: .now()) == .success {
        DispatchQueue.main.async {
            // Some processing...

            self.metadataObjectsOverlayLayersDrawingSemaphore.signal()
        }
    }
}

Context of the code: This is the delegate method when using video capture to detect a QR code (or any other code). Because it is triggered many times per second (if the camera stays on the same QR code), some kind of timeout is needed.

But how does DispatchSemaphore.wait(timeout: .now()) work? And why check if it is .success?

like image 647
Kalzem Avatar asked Apr 03 '18 14:04

Kalzem


1 Answers

The purpose is what the comment says:

wait() is used to drop new notifications if old ones are still processing, to avoid queueing up a bunch of stale data.

and it works as follows:

  • The semaphore is created with a value of one.
  • When metadataOutput is called the first time, wait(timeout: .now()) succeeds and decrements the value of the semaphore to zero. The processing of the data begins.
  • If metadataOutput is called again before the processing has completed, the semaphore still has a value of zero. Then wait(timeout:) would wait for the semaphore to become positive again, but since the timeout value is now(), it fails immediately and returns .timedOut. The effect is that the incoming data is ignored, the metadataOutput callback method returns immediately.
  • When the data processing on the has completed, the semaphore is signaled, which increases the value to one. As a consequence, the next time the callback is called, waiting for the semaphore will succeed and the data is processed again.

So in short:

  • wait(timeout: .now()) returns .success if a previously submitted block has signaled completion, in that case a new block is submitted for processing the incoming data.
  • wait(timeout: .now()) returns .timedOut if a previously submitted block is still running, in that case the incoming data is ignored.
like image 166
Martin R Avatar answered Sep 26 '22 13:09

Martin R