Safe to hold locks in NSNotification handlers?

"A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification."


Therefore, is it safe to block in a NSNotification handler registered with the default NSNotificationCenter for a system notification? (ex. AVAudioSessionInterruptionNotification)

Accepted Reply

There’s no simple yes or no answer here. It depends on the context in which the notification was posted and what locks are involved. For example, doing sync/blocking file I/O is unlikely to cause problems, but calling back into the subsystem that posted the notification could well get you into trouble.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

There’s no simple yes or no answer here. It depends on the context in which the notification was posted and what locks are involved. For example, doing sync/blocking file I/O is unlikely to cause problems, but calling back into the subsystem that posted the notification could well get you into trouble.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

@eskimo Thanks again for taking the time 🙂.


As an example, I want to hold a program-created pthread mutex in a notification handler for an AVAudioSessionInterruptionNotification (most of the AVAudioSession notification handlers all need to touch the same objects: ex. the shared AVAudioSession and my Audio Unit)


Nothing fancy here. Perhaps it is better to spinlock instead? Feels very signal-y

Perhaps it is better to spinlock instead?

No. Spinlocks are pretty much never the right answer.

The question you have to ask yourself is, what will the thread that posted the notification do if you block it? There two potential sources of problems here:

  • Will that thread tolerate delays?

  • Is that thread itself holding locks that could result in you deadlocking?

I don’t know enough about AV Foundation to answer these questions for

AVAudioSessionInterruptionNotification
. In situations like this I usually turn the question around and ask, do I have to process the notification synchronously? If not, I bounce the notification to my own thread, where I can set things up so that it’s safe to block (or queue, where I know things are serialised by the queue).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hey eskimo.


"Will that thread tolerate delays?"


Precisely the question I'm trying to ask - ex. scared of what will happen if I make a system thread block on a mutex. Despite it's obvious drawbacks, spinlocking doesn't have this problem, and only makes my handler suseptible to timeouts.


Actually - the documentation says "posted on the main thread" for each AVAudioSession*Notification - so I should be fine..

Despite it's obvious drawbacks, spinlocking doesn't have this problem, and only makes my handler suseptible to timeouts.

I’m not sure what you mean by the term “spinlock” but it doesn’t seem to match up with the standard definition, namely, “a spinlock is a lock which causes a thread trying to acquire it to simply wait in a loop (“spin”) while repeatedly checking if the lock is available”. That is, the key difference between a spinlock and a normal lock is that the thread doesn’t sleep while waiting, and I can’t see how that would help in this situation at all.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

@eskimo That's precisely what spinlock means, yes. I'm not some hobbyiest 😝.


I never "claimed" they were better - just brought them up for discussion! Sometimes they can be handy! I don't understand the context in which all NSNotifications are delivered - but since you have a better view on that side of the fence and think it's a bad idea, I'll trust your judgement!


My thinking was it may be illegal/unsafe to put a system thread used to call a handler, to sleep -- but might be able to "get away with" (i.e. obviously it's a little hacky) just having, what would appear to be from the system's POV, a long running (probably not even *that* long running) CPU-intensive task. Hence, the only thing that would prevent such a solution from "working" was if the system said "OK - that's long enough!". Can't say it is playing nice with the system - but as I said - just brought it up for discussion! I'm totally OK with never putting them in 🙂


Anyways - seems in my case, seems like they are all posted to the main thread, so I don't need a lock 🙂


Thanks again for your help @eskimo, very much appreciate your insights!

Sometimes they can be handy!

Spinlocks are the wrong answer is almost all circumstances. Blocking locks have a fast path that makes them as efficient as spinlocks in the uncontested case, and spinlocks behave very badly in the contested case. Specifically, spinlocks have no ability to deal with priority inversions.

You should take a look at the comments in the (now deprecated)

<libkern/OSSpinLockDeprecated.h>
and (its replacement)
<os/lock.h>
.

I don't understand the context in which all NSNotifications are delivered.

In the classic NSNotification architecture, notifications are synchronous and occur on the thread of the caller. That is, the thread that calls

-postNotification:
actually calls each of the observers in turn. This can be confusing but it’s a super useful property, especially if the poster guarantees to post on the main thread.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"