开发者

Objective C equivalent of intern() in java

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


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.


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.


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

Thanks all


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜