If a method is called at the same time twice, how to execute it only once?

We have a method in the iPhone SDK, which is a delegate method. The problem is that the OS calls this method twice at the same time. This method makes a heavy climb, so I do not want to execute the logic twice. What is a good way to detect this and prevent one of the two from starting?


I forgot to mention that it is called from different threads.

+4
source share
8 answers

One method is the BOOL member that you set when you enter the method and clear it. If the variable is set to write, you know that it is already running and may just return.

Assuming you are being called from multiple threads, you need to block access to this critical validation / configuration area. NSLock is good for this.

The code below has two implementations: myMethod1, which uses NSLock, and myMethod2, which shows the use of @synchronize.

@interface MyClass : NSObject { NSLock* theLock; BOOL isRunning; } @end @implementation MyClass -(id)init { self = [super init]; if(self != nil) { theLock = [[NSLock alloc] init]; isRunning = NO; } return self; } -(void)dealloc { [theLock release]; [super dealloc]; } // Use NSLock to guard the critical areas -(void)myMethod1 { [theLock lock]; if(isRunning == YES) { [theLock unlock]; // Unlock before returning return; } isRunning = YES; // Do fun stuff here isRunning = NO; [theLock unlock]; } // This method uses @synchronize -(void)myMethod2 { @synchronized(self) { if(isRunning == YES) { return; } isRunning = YES; // Do stuff here. isRunning = NO; } } @end 
+9
source

Wow. This answer is correct, but it is too reworked. Just use @synchronized() .

foo.h:

 @interface Foo { id expensiveResult; } - (void) bar; @end 

Foo.m:

 @implementation Foo - (void) bar { @synchronized(self) { if (expensiveResult) return expensiveResult; .... do expensive stuff here .... expensiveResult = [theResult retain]; } return expensiveResult; } @end 

If you have multiple instances of Foo and want to guarantee exclusivity in all instances, create a global variable in +(void)initialize - NSString will do everything right - and @synchronized() .

However, your question raises a much more important question. In particular, there is never a case when the same method will be called twice at the same time, unless you explicitly set up the application for this to happen.

The answer provided the sound more as a fix for the symptom than a fix for the real problem.

Note. It relies on an expensiveResult zero, which will be the same as all iVars when instantiating. Obviously, the reset value of ivar is zero if you want to recount.

+5
source

The simplest is setting a flag.

 - (void)action { if (flag_is_set == NO) { flag_is_set = YES; do stuff flag_is_set = NO; } } 

it is not 100% safer, although you may get some rare cases of blocking.

If you can handle some hibernation in a thread, use nslock

 - (id)init { theLock = [[NSLock alloc] init]; } - (void)action { [theLock lock]; doStuff [theLock unlock]; } 

When thread 2 arrives at a lock call, and thread 1 already has it, it will sit in the run loop until the lock is released and then starts again. If you have a user interface in this thread, the application will be frozen

+2
source

Some of the answers above are acceptable solutions to the problem of multiple "producer" threads calling the same function at the same time, but you might be better off figuring out why multiple threads are calling the same code block at the same time. Maybe you assign this delegate multiple event handlers or the like. You probably noticed that this is due to the fact that some general state is distorted or the output of the function is incorrect for the "global" state at the end of the function. Putting bandanas upon the fact of 2 streams in a given function (when it is clear that streams were not the main problem when it was written) will not necessarily give you the correct results. Threading is not trivial, and a joint state makes it very difficult to get it right, make sure you fully understand why this happens before just trying to attack it.

If we say that if you use the gang approach, then it is probably better to do this with a lock, where each thread ultimately gets the opportunity to execute a function, rather than release it if this function is already running, since the client code will look like this long, and the "weightlifting" process is complete, and they can check the results.

+2
source

If these calls are synchronized, so that happens only once, you can simply have a variable in your class called "initialized" that starts with false and sets during initialization:

 if (!initialized) { // handle delegated call initialized = 1; } 

If a delegate is called from multiple threads, you need to put all this in a mutex block.

0
source

Here you can use objective-c locks as mutexes.

http://rosettacode.org/wiki/Mutex#Objective-C

Mutexes exist to provide mutually exclusive access to a specific block of code. Within the method, you can do something like:

 [methodLock lock]; //Blocks and waits until the lock is released //...do stuff [methodLock unlock]; //Releases the lock once the code has executed. 

This ensures that only one thread will be allowed in the // do stuff block of code.

EDIT: I read the question again; within the lock, I would check the flag to see if it starts (using BOOL)

0
source

Use pthread_once() - it was clearly intended for this. The only problem is that the function you pass cannot accept any arguments, so you need to use global variables to pass information to it.

0
source

If they are called at the same time, I think they are called in threads?

What you can do is define a BOOL @property (e.g. isRunning ) with an atomic attribute (set by default). This way, this property can be safely obtained from different threads, and then you can do something like:

 if (isRunning) return ; isRunning = YES; // ... // Your code here // ... usRunning = NO; 

You can also make sure that you are doing the right thing. If your method is called twice, maybe you are doing something wrong (or maybe this is normal, I donโ€™t know what you are doing;))

-one
source

All Articles