views:

100

answers:

4

Is there a way in objective C that I can define a static int that is thread safe?

for example if I have class called Session that has:

static unsigned int session_id = 1000;

- (int) generateSessionID{
        return session_id++;
}

I am constructing session objects from different threads, each session object should have a unique id.

A: 

If you're talking Cocoa, the mutex functionality there is provided by NSLock and NSRecursiveLock.

In order to properly protect non-atomic resource, you need these mutexes, lest multiple threads may try to change the data at the same time (leading to corruption) or use the data in a half-changed state (leading to invalid data).

Your code would look something like this:

static NSLock session_id_lock;
static unsigned int session_id = 1000;

- (int) generateSessionID{
    int new_id;
    [myLock lock];
    new_id = session_id++;
    [myLock unlock];
    return new_id;
}

If you're not using Cocoa (or what little Cocoa programming I remember from my brief interlude with an iMac is so dimly remembered that it's near useless), just use the concept, translating it to whatever language or framework you have:

  • lock the mutex before using or changing a protected resource.
  • use or change the resource.
  • unlock the mutex.
  • bonus advice 1: lock the mutex as late as possible and unlock it as soon as possible.
  • bonus advice 2: only lock what you need so you avoid unnecessary delays.

Explaining that last point some more: if you synchronise on self for two totally unrelated things (say a session ID and a user ID), they will block each other despite the fact that it's not necessary to do so. I would prefer two separate mutexes to keep the granularity low.

Of course, if you only have a mutex on the session ID alone (but see below for caveat), feel free to use synchronized(self) but I'd prefer to do it my way so I wouldn't get caught out adding another protected resource later.

In any case (this is the caveat mentioned), you will probably find that synchronising on self would not adequately protect a static variable, which would be shared across multiple objects. The mutex should belong to the data rather than whatever is using it.

paxdiablo
I am coming from Java world, where you simply can do: static synchronized int generateID(){return sessionId++}. is this will be compatible if i do -(int) generateSessionID{synchronized(self){return session_id++;}}?
Unis
I would think that would work okay though a lock on self (the object) is probably more broad than I would do. Instead, I would prefer a specific mutex so as to avoid mutex delays that were unnecessary (see my added bonus advice).
paxdiablo
@user489579 Close, but you don't want to synchronize on `self` for an instance method that's accessing a static variable; maybe sync on `[self class]`, or on an object that's directly associated with the value you're modifying (e.g. wrap the int in an NSNumber and sync on the NSNumber).
David Gelhar
Ah, good point, I forgot it was static so could be used by _multiple_ objects - I'll adjust the answer.
paxdiablo
David, I see your point and i thought of wrapping or declaring the a NSNumber instead of int, but where/when exactly you will release the NSNumber as it will be (can be) accessed by constructing other objects to generate their ids.
Unis
I wouldn't think you'd need to worry about releasing it. You could create it but once created it doesn't go away.
David Gelhar
+3  A: 

I think you're better off using atomic operations to modify session_id. A previous question talks about atomic increment/decrement operations for OS X, and this page talks about the OSAtomic header file. Atomic operations on integers, something that's readily hardware-supported, will probably be substantially faster than using locking constructs.

Wyatt Anderson
+1  A: 

There are many options, including (from high-level to low-level) the @synchronized Objective-C directive, NSLock, pthread_mutex_lock, and atomic operations.

Read the "Synchronization" section of the Threading Programming Guide for details.

David Gelhar
A: 

Use @synchronize on the object instance.

- (int) generateSessionID
{
    @synchronized (self)
    {
        session_id++;
    }
    return session_id;
}
jojaba
No. You need to synchronize on the class object for variables defined with file static scope.
JeremyP