NSThread Not Loading Selector Method - objective-c

In the initialization method of a class I am declaring the thread as such:
NSThread* myThread = [[[NSThread alloc] initWithTarget:self selector:#selector(m_run_thread) object:nil] autorelease];
[myThread start];
I also have a boolean value which is set to NO. Later on in the code I set the boolean value to YES.
bool_run_progress_thread = YES;
The contents of the method m_run_thread is as follows:
-(void) m_run_thread
{
if (bool_run_progress_thread)
{
//do processing here
}
bool_run_progress_thread = NO;
}
The problem is that the method m_run_thread is never being accessed. What am I doing wrong?
P.S. I have also tried to set up the Thread using the following (and older)method:
[NSThread detachNewThreadSelector:#selector(m_run_thread)
toTarget:self
withObject:nil];
... but to no avail as well.

"...and I am only getting it to show once" Yes, that's exactly how it should be. After being started, a thread runs once from its start to its end (ignoring errors here for the moment), and having reached the end, the thread is essentially dead and gone.
If you want the thread to repeat its execution, you have to prepare for that yourself:
- (void) m_run_thread
{
for (;;)
{
if (bool_run_progress_thread)
{
//do processing here
bool_run_progress_thread = NO;
}
}
}
But there is still a lot wrong with this code: essentially, when run, the code forms a busy waiting loop. Assuming, that bool_run_progress_thread is only ever true for short periods of time, the background thread should be sleeping most of the time. Insead, if you try the code as its stands, it will instead consume CPU time (and lots of it).
A better approach to this would involve condition variables:
#class Whatsoever
{
NSCondition* cvar;
BOOL doProgress;
...
}
...
#end
and
- (void) m_run_thread
{
for (;;)
{
[cvar lock];
while (!doProgress)
{
[cvar wait];
}
doProgress = NO;
[cvar unlock];
... do work here ...
}
}
and in order to trigger the execution, you'd do:
- (void) startProgress
{
[cvar lock];
doProgress = YES;
[cvar signal];
[cvar unlock];
}
Doing things this way also takes care of another subtle problem: the visibility of the changes made to the global flag (your bool_run_progress_thread, my doProgess). Depending on the processor and its memory order, changes made without special protection might or might not become (ever) visible to other threads. This problem is taken care of by the NSCondition, too.

Related

Draw the contents of an array modified in the background

I have a background thread that runs and modifies the contents of a NSMutableArray within an object. This takes a long time to run (several hours) and I periodically want to draw the contents of an array within the drawRect of a NSView to check on progress and see the intermediate results.
My object has a protocol with a method called: didChange:
// How I start my background thread
[self performSelectorInBackground:#selector(startProcessing) withObject:nil];
- (void)startProcessing {
myObject.delegate = self;
[myObject start];
}
// My protocol implementation
- (void)myObjectDidChange:(myObjectClass *)sender {
[myView setNeedsDisplay:YES];
}
// My View's drawRect (pseudo code)
- (void)drawRect {
[myObject drawInContext:context];
}
All works, except that the NSMutableArray backing all this is being changed whilst the drawing takes place. How should I do this? Do I somehow pause the processing in the background thread whilst the update is taking place?
EDIT: This is the sort of display I am drawing (although much more complicated):
Any help appreciated.
If you are doing something in background thread and you want to update UI, its usually done on the main thread, so in your object did change you would do it, probably like this:
// My protocol implementation
- (void)myObjectDidChange:(myObjectClass *)sender {
dispatch_async(dispatch_get_main_queue(), ^{
[self drawRect]; //Or any drawing function you are trying to do
});
}
I have done it using NSLock to lock the outer loop of the start and the drawInContext methods. I am still not sure if this is the best approach and will not accept this answer for a few days in case there is a better answer out there.
- (void)start {
for(int i=0; i < MAX; i++) {
[self.updateLock lock];
....
[self.updateLock unlock];
}
}
- (void)drawInContext:(CGContextRef)context {
[self.updateLock lock];
...
[self.updateLock unlock];
}

Is it possible to check if an NSThread is blocked?

I've always been interested in how to write the following code to use it for unit testing:
Is it possible to extend NSThread with a method that would check if a particular thread is blocked?
Right now I'am working with NSCondition: Xcode shows me the chain which is called by -wait to block the thread:
[NSCondition wait]
pthread_cond_wait$UNIX2003
_pthread_cond_wait
__psynch_cvwait
Besides checking the locks done by NSCondition, if it is even possible, I would highly appreciate method working also for any other blocking capabilities (dispatch semaphores, condition locks, sleeping threads and so on, ) - I have no idea about Objective-C internals, if maybe they could be catched by one method or each needs its own.
Here is a simple example of what I would like to achieve. The mysterious method is called isBlocked.
// Some test case
// ...
__block NSThread *thread;
NSCondition *condition = [NSCondition alloc] init];
dispatch_async(someQueue(), ^{
thread = NSThread.currentThread;
[condition lock];
[condition wait];
[condition unlock];
});
while(1) {
NSLog(#"Thread is blocked: %d", thread.isBlocked);
}
Note: I am not good at C and all this low-level POSIX stuff, so, please, be verbose.
Note 2: I am interested in solutions working for dispatch queues as well: if someone can show me how to test the fact that someQueue() is blocked by -[NSCondition wait] (not the fact that it is going to be blocked (fx hacking some code before -[condition wait] is run and the block is set), but the fact that thread/queue is blocked), I will accept this as an answer as much like I would do with working -[NSThread isBlocked] method.
Note 3: Suspecting bad news like "it is not possible", I claim that any ideas about catching the fact that -[condition wait] was run and the thread was set blocked (see Note 2) are appreciated and can be also accepted as an answer!
UPDATE 1 in address to the nice answer by Richard J. Ross III. Unfortunately, his answer does not work in my original example, the version which is closer to my real work (though it does not differ much from the example I've initially provided - sorry that I didn't include it in the first edition of the question):
// Example
// Here I've bootstrapped Richard's isLocking categories for both NSThread and NSCondition
// ...
// somewhere in SenTesting test case...
__block NSThread *thread;
NSCondition *condition = [NSCondition alloc] init];
__block BOOL wePassedBlocking = NO;
dispatch_async(someQueue(), ^{
thread = NSThread.currentThread;
[condition lock];
[condition wait];
[condition unlock];
wePassedBlocking = YES; // (*) This line is occasionally never reached!
});
while(!thread.isWaitingOnCondition); // I want this loop to exit after the condition really locks someQueue() and _thread_ __.
// sleep(1);
[condition lock];
[condition broadcast]; // BUT SOMETIMES this line is called before -[condition wait] is called inside someQueue() so the entire test case becomes blocked!
[condition unlock];
while(!wePassedBlocking); // (*) And so this loop occasionally never ends!
If I uncomment sleep(1) test begins working very stable without any occasional locks!
This leads us to the problem, that Richard's category does set state exactly one line before the actual blocking is done meaning that sometimes test case's main thread catches this new state before we actually have someQueue/thread blocked because Richard's code does not contain any synchronization mechanisms: #synchronized, NSLock or something like that! I hope I am making a clear explanation of this tricky case. For anyone who has doubts about what I've posted here, I would say that I have been also experimenting with multiple queues and even more complex cases, and if needed I'm ready to provide more examples. Richard, thanks again for your effort, let's think more together, if you understand these my points!
UPDATE 2
I see the dead-end paradox: obviously, to really set the state of waitingOnCondition we need to wrap this state's change inside some synchronization closures, but the problem is that the closing one, unlocking the synchronization lock, should be called after -[condition wait], but it can't, because the thread is already blocked. Again, I hope I am describing it pretty clear.
Here you go! It won't detect threads being waited on by anything other than -[NSCondition wait], but it could easily be extended to detect other kinds of waiting.
It's probably not the best implementation out there, but it does in fact work, and will do what you need it to.
#import <objc/runtime.h>
#implementation NSThread(isLocking)
static int waiting_condition_key;
-(BOOL) isWaitingOnCondition {
// here, we sleep for a microsecond (1 millionth of a second) so that the
// other thread can catch up, and actually call 'wait'. This time
// interval is so small that you will never notice it in an actual
// application, it's just here because of how multithreaded
// applications work.
usleep(1);
BOOL val = [objc_getAssociatedObject(self, &waiting_condition_key) boolValue];
// sleep before and after so it works on both edges
usleep(1);
return val;
}
-(void) setIsWaitingOnCondition:(BOOL) value {
objc_setAssociatedObject(self, &waiting_condition_key, #(value), OBJC_ASSOCIATION_RETAIN);
}
#end
#implementation NSCondition(isLocking)
+(void) load {
Method old = class_getInstanceMethod(self, #selector(wait));
Method new = class_getInstanceMethod(self, #selector(_wait));
method_exchangeImplementations(old, new);
}
-(void) _wait {
// this is the replacement for the original wait method
[[NSThread currentThread] setIsWaitingOnCondition:YES];
// call the original implementation, which now resides in the same name as this method
[self _wait];
[[NSThread currentThread] setIsWaitingOnCondition:NO];
}
#end
int main()
{
__block NSCondition *condition = [NSCondition new];
NSThread *otherThread = [[NSThread alloc] initWithTarget:^{
NSLog(#"Thread started");
[condition lock];
[condition wait];
[condition unlock];
NSLog(#"Thread ended");
} selector:#selector(invoke) object:nil];
[otherThread start];
while (![otherThread isWaitingOnCondition]);
[condition lock];
[condition signal];
[condition unlock];
NSLog(#"%i", [otherThread isWaitingOnCondition]);
}
Output:
2013-03-20 10:43:01.422 TestProj[11354:1803] Thread started
2013-03-20 10:43:01.424 TestProj[11354:1803] Thread ended
2013-03-20 10:43:01.425 TestProj[11354:303] 0
Here is a solution using dispatch_semaphore_t
PGFoo.h
#import <Foundation/Foundation.h>
#interface PGFoo : NSObject
- (void)longRunningAsynchronousMethod:(void (^)(NSInteger result))completion;
#end
PGFoo.m
#import "PGFoo.h"
#implementation PGFoo
- (void)longRunningAsynchronousMethod:(void (^)(NSInteger))completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(5);
completion(1);
});
}
#end
Test Methods
- (void)testThatFailsBecauseItIsImpatient {
PGFoo *foo = [[PGFoo alloc] init];
__block NSInteger theResult = 0;
[foo longRunningAsynchronousMethod:^(NSInteger result) {
theResult = result;
}];
STAssertEquals(theResult, 1, nil);
}
- (void)testThatPassesBecauseItIsPatient {
PGFoo *foo = [[PGFoo alloc] init];
__block NSInteger theResult = 0;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[foo longRunningAsynchronousMethod:^(NSInteger result) {
theResult = result;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
STAssertEquals(theResult, 1, nil);
}
By using a dispatch_semaphore_t you can "track" whether a thread that is waiting on that semaphore is blocked. For every call of dispatch_semaphore_wait the semaphore's count is decremented and the thread waits until a call of dispatch_semaphore_signal is made, when dispatch_semaphore_signal is called the semaphore's count is incremented, if the count is incremented to a value greater than -1 the thread continues.
This solution fails to answer your question about checking whether an NSThread is "blocked" but I think it provides what you are reaching for, assuming you're not reaching to check on NSThread instances that are maintained within an existing framework.

Synchronizing a Block within a Block?

I'm playing around with blocks in Objective-C, trying to come up with a reusable mechanism that will take an arbitrary block of code and a lock object and then execute the block of code on a new thread, synchronized on the provided lock. The idea is to come up with a simple way to move all synchronization overhead/waiting off of the main thread so that an app's UI will always be responsive.
The code I've come up with is pretty straightforward, it goes like:
- (void) executeBlock: (void (^)(void))block {
block();
}
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}
So for example, you might have some methods that go like:
- (void) addObjectToSharedArray:(id) theObj {
#synchronized(array) {
[array addObject: theObj];
}
}
- (void) removeObjectFromSharedArray:(id) theObj {
#synchronized(array) {
[array removeObject: theObj];
}
}
Which works fine, but blocks the calling thread while waiting for the lock. These could be rewritten as:
- (void) addObjectToSharedArray:(id) theObj {
[self runAsyncBlock:^{
[array addObject: theObj];
} withLock: array];
}
- (void) removeObjectFromSharedArray:(id) theObj {
[self runAsyncBlock: ^{
[array removeObject: theObj];
} withLock:array];
}
Which should always return immediately, since only the background threads will compete over the lock.
The problem is, this code crashes after executeBlock: without producing any output, error message, crash log, or any other useful thing. Is there something fundamentally flawed in my approach? If not, any suggestions with respect to why this might be crashing?
Edit:
Interestingly, it works without crashing if I simply do:
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock();
}
But of course this will block the calling thread, which largely defeats the purpose. Is it possible that blocks do not cross thread boundaries? I would think not, since that would largely defeat the purpose of having them in the first place.
remember to call [block copy] otherwise it is not correctly retained because block are created on stack and destroyed when exit scope and unless you call copy it will not move to heap even retain is called.
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
block = [[block copy] autorelease];
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock = [[syncBlock copy] autorelease];
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}

How can I make a method stall for a fixed amount of time?

I have an app that calls a sometimes-fast, sometimes-slow method. I know an upper bound for how long it will take (2 seconds). I'd like to set a timer to start when the method is called, run the code, but then not produce the output until 2 seconds has passed, no matter how long it actually takes. That way the user perceives the action as always taking the same amount of time. How can I implement this?
What I would like is something along the lines of this:
-(IBAction)doStuff {
// START A TIMER, LOOK BUSY
[activityIndicator startAnimating];
... real work happens here ...
... NSString *coolString gets assigned ...
// WHEN TIMER == 2 SECONDS, REVEAL COOLNESS
[activityIndicator stopAnimating];
[textField setText:coolString];
}
There are a couple of ways to delay an action in Cocoa. The easiest may be to use performSelector:withObject:afterDelay:. This method sets up a timer for you and calls the specified method when the time comes. It's an NSObject method, so your objects all get it for free.
The tricky part here is that the first method will block the main thread, so you need get it onto a background thread, and then get back to the main thread in order to update the UI. Here's a stab at it:
// Put the method which will take a while onto another thread
[self performSelectorInBackground:#selector(doWorkForUnknownTime)
withObject:nil];
// Delay the display for exactly two seconds, on the main thread
[self performSelector:#selector(displayResults)
withObject:nil
afterDelay:2.0];
- (void)doWorkForUnknownTime {
// results is an ivar
results = ...; // Perform calculations
}
- (void)displayResults {
if( !results ){
// Make sure that we really got results
[self performSelector:#selector(displayResults:)
withObject:nil
afterDelay:0.5];
return;
}
// Do the display!
}
The only other thing I can think of is to store the time that the "work" method is called in an NSDate, and check how long it took when you get the results. If it isn't two seconds yet, sleep the background thread, then call back to the main thread when you're done.
[self performSelectorInBackground:#selector(doWorkForUnknownTime:)
withObject:[NSDate date]];
- (void)doWorkForUnknownTime:(NSDate *)startTime {
// All threads must have an autorelease pool in place for Cocoa.
#autoreleasepool{
// This will take some time
NSString * results = ...; // Perform calculations
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:startTime];
if( elapsedTime < 2.0 ){
// Okay to do this to wait since we're on a background thread,
// although not ideal; sleeping threads are kind of wasteful.
// Try not to do this a lot.
sleep(2.0 - elapsedTime);
}
// Don't forget to retain results on the main thread!
[self performSelectorOnMainThread:#selector(displayResults:)
withObject:results
waitUntilDone:YES];
// [results release]; // if necessary
}
}
[self performSelector:#selector(myfunc) withObject: afterDelay:];
should help.
-(IBAction)doStuff {
// START A TIMER, LOOK BUSY
[activityIndicator startAnimating];
... real work happens here ...
... NSString *coolString gets assigned ...
// WHEN TIMER == 2 SECONDS, REVEAL COOLNESS
[self performSelector:#selector(revealCoolnessWithString:) withObject:coolString afterDelay:2];
}
- (void)revealCoolnessWithString:(NSString *)coolString
{
[activityIndicator stopAnimating];
[textField setText:coolString];
}
Hope this helps

NSInvocation Leaks

I am trying to setup an NSInovcation system to launch selectors into background threads using performSelectorInBackground: - So far everything is successful when running the system on instance methods (-), but I also want to support class methods (+). I have adjusted my code to provide an invokeInBackgroundThread for both types of class and everything worked except for one problem. When the class methods are invoked I get my console flooded with "autoreleased with no pool in place" messages. No idea what is causing it. The code which is based off the DDFoundation open source project is shown below.
#implementation NSObject (DDExtensions)
...
+ (id)invokeInBackgroundThread
{
DDInvocationGrabber *grabber = [DDInvocationGrabber invocationGrabber];
[grabber setInvocationThreadType:INVOCATION_BACKGROUND_THREAD];
return [grabber prepareWithInvocationTarget:self];
}
- (id)invokeInBackgroundThread
{
DDInvocationGrabber *grabber = [DDInvocationGrabber invocationGrabber];
[grabber setInvocationThreadType:INVOCATION_BACKGROUND_THREAD];
return [grabber prepareWithInvocationTarget:self];
}
...
...
- (void)forwardInvocation:(NSInvocation *)ioInvocation
{
[ioInvocation setTarget:[self target]];
[self setInvocation:ioInvocation];
if (_waitUntilDone == NO) {
[_invocation retainArguments];
}
if (_threadType == INVOCATION_MAIN_THREAD)
{
[_invocation performSelectorOnMainThread:#selector(invoke)
withObject:nil
waitUntilDone:_waitUntilDone];
} else {
[_invocation performSelectorInBackground:#selector(invoke)
withObject:nil];
}
}
...
+(void)doSomething;
[[className invokeOnBackgroundThread] doSomething];
Main thread has autorelease pool by default, if you start extra thread - it's your job to create the pool. Actually, nothing complicated here, just
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// Work...
[pool release];
Also, if you have a lot of threads, I'd suggest you to take a look at NSOperation instead of running threads with [performSelectorInBackground]. NSOperation (with wrapping queue) is more flexible solution for such tasks.