2

I got to implement some synchronization algorithms depending on strings. I mean two threads have to be synchronized and the pair of threads both depend on a string value (one pair of threads for String A, one pair for String B, and so on).

In java, I could implement the algorithm using the method intern to get a single lock object that is shared by both threads. Java pulls all litteral in a jvm built-in pool and interne allows to transform any string created dynamically into a litteral in the pool.

I understood that there is also a pooling mechanism in Objective C.

But is there any equivalent to intern() in Java, i.e a way to transform a normal String into a litteral String from the pool of String constants. To get the reference to this unique String litteral so that both my threads could get synchronize on the same object.

I know there are some work around but they all imply a lot of String comparisons that I would like to avoid. (Although I believe intern does it but in an optimized way...)

To explain my problem in more general term : I want to avoid having a Dictionnary that maps a String to a lock. Java allows me to do that thanks to intern as the String litteral (pooled) will become the lock. Is there any equivalent or must I use this map.

Thanks folks, Stéphane

Community
  • 1
  • 1
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • 1
    I don't think it is a good idea to synchronize over a string literal. Over a string variable OK, but on a literal, I don't know... But maybe I am wrong. – Petar Minchev Sep 08 '11 at 08:15
  • 2
    It might be worth describing what your higher level goal is. What do you want to achieve, in general terms ? Your question sounds like you've got a very specific solution in mind for a problem that might be better solved through other means in Objective-C/Cocoa. – DarkDust Sep 08 '11 at 08:29

4 Answers4

2

I program regularly in both Java and Objective-C.

First, what you describe seems a less-than-ideal way to share a lock. It's tricky, it's brittle, and it will confuse other coders not so intimate with how String interning works. Why not just have a lock object in one class exposed to the other as a constant?

public class Foobar {

    public static final Object LOCK = new Object();

    public void doLockedStuff() {
        synchronized (LOCK) {
            // code here
        }
    }

}

public class Barfoo {
    public void doLockedStuff() {
        synchronized (Foobar.LOCK) {
            // code here
        }
    }
}

And then you can adopt a similar approach in Objective-C - a class method exposing a shared LOCK object.

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • I believe any good solution even difficult, as long as it is well documented, is really valid. – Snicolas Sep 08 '11 at 08:41
  • this approach doesn't relate to the question sorry – Snicolas Sep 08 '11 at 16:03
  • It does relate in that I think using interned Strings is not good for locking in either Java or Objective-C. Instead you should use a shared object created specifically for locking. – Steve McLeod Sep 08 '11 at 16:48
2

I think mapping the strings to the locks they represent is your best bet.

You don't want to lock on the String itself (or an interned version) because it's a shared object in the JVM. You don't know if another component in the JVM is doing the same thing, which could cause a deadlock.

Java Concurrency in Practice describes this better, but I can't find a reference at the moment.

The map containing your locks won't incur a large performance problem if you use a HashMap because Strings are immutable and the hash code of the String will likely only have to be calculated once.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129
2

I finally used a dictionnary that binds every string to a conditionnal lock.

Thanks all

Snicolas
  • 37,840
  • 15
  • 114
  • 173
2

Without suggesting that is the best way to generate the locks that you are looking for but here is a little hack to give you the effect you want:

NSString *stringA = [NSString stringWithString:@"Hello"];
NSString *stringB = [NSString stringWithFormat:@"%@l%@",@"Hel",@"o"];
NSString *stringC = [NSString stringWithFormat:@"Hell%@", @"o"];

NSLog(@"%p / %p / %p", stringA, stringB, stringC);

NSNumber *lockA = [NSNumber numberWithUnsignedInteger:stringA.hash];
NSNumber *lockB = [NSNumber numberWithUnsignedInteger:stringB.hash];
NSNumber *lockC = [NSNumber numberWithUnsignedInteger:stringC.hash];

NSLog(@"%p / %p / %p", lockA, lockB, lockC);

You will notice that eventhough the strings have different addresses, their corresponding NSNumbers don't. That's because NSNumbers for a given number is a singleton.

You can now use @synchronize() on these "lock" objects.

-- Edit --

The fact that NSNumbers are singletons for a given value is an internal detail to the implementation, which is one reason why it might be a good idea to shop around for a real locking mechanism such as a dictionary indexed by NSString for example.

aLevelOfIndirection
  • 3,522
  • 14
  • 18