views:

176

answers:

2

I'm working on a relatively simple iPhone application that has a multi-round Timer with a number of settings such as the number of rounds and round length. We allow certain settings to be upated while the timer is running which means the timer may be reading from the same memory that the settings are writing. There are no critical sections of code where multiple threads will be executing at the same time but code from the settings may be trying to write memory the timer is reading from.

In terms of a simple example, let's say we a global variable foo and there is an NSTimer method which looks as follows:

-(void)timerTick { NSString *x = foo; }

then in the settings code, we do this while the timer is running:

foo = @"test";

Will it be enough to make foo atomic in this application or do we need some kind of locking scheme?

Thanks.

A: 

You can either @synchronized or NSLock/NSRecursiveLock/NSConditionLock your reads and writes. Better to use the standard ways of doing it than risking to prematurely publish a nil foo.

David Sowsy
This is unnecessary for NSTimers
Rhythmic Fistman
+4  A: 

Usually you don't have to lock when you use NSTimer in the usual way.

In more detail, when you create the timer with NSTimer's scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, the resulting timer is added to the run loop of the thread in which you create the timer. So, if you create the NSTimer instance on the main thread this way, the firing of the timer is handled as a part of the main event loop, so the callback you registered is called on the main thread, not on another thread. So, if you don't create any thread yourself, there's no concern at all about locking etc.

For more details, read this.

Yuji
“… the resulting timer is added to the main run loop.” No, not necessarily. It is added to the *current* run loop—i.e., the run loop on **the current thread, which may not be the main thread**. http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/Reference/Reference.html#//apple_ref/occ/clm/NSRunLoop/currentRunLoop
Peter Hosey
I think this was more in line with what you meant: “… if you don't create any thread yourself, there's no concern at all about locking etc.” This is correct: If you haven't created another thread, then the main thread is the current thread, so the timer will be on the main thread's run loop *in that case*. If you wanted to run a timer on a thread, you would have to create the thread yourself, then create and schedule the timer on that thread. (And then you would have to think about synchronization.)
Peter Hosey
Yes you're perfectly right, Peter. Thank you for pointing it out.
Yuji
I create no other threads in the app so then I guess synchronization isn't need. However, atomicity is still needed right? It seems like it would be possible for the Timer tick method to fire and try to read "foo" while I'm in the middle of of updating "foo" from settings then end up with "bad" data unless foo is atomic. Am I accurate? Thanks for all the help so far.
NickDK
NickDK: No. The timer will only fire while the run loop is running. The run loop is paused while something else (e.g., an event, which you're handling) is firing. The only way for the timer callback to run while the settings update is also running is with them on separate threads. (Well, or call the callback yourself/fire the timer from a signal handler or atexit handler. But it's unlikely that you'll have a reason to do either, and if you ever do do it, you'll almost certainly know you're doing it.)
Peter Hosey