Threads in Objective C - objective-c

-(void)startThread {
m_bRunThread = YES;
if(m_bRunThread) {
NSThread* myThread = [[NSThread alloc]initWithTarget:self selector:#selector(display) object:theConditionLock];
[myThread start];
/*((WaitForSingleobject(event,1500) != WAIT_OBJECT_O) || !m_bRunThread) {
m_bRunThread = false;
Trace(_T("Unable to start display Thread\n"));
}*/
}
[self insert];
}
-(void)insert {
[theConditionLock lockWhenCondition:LOCK];
NSLog(#"I'm into insert function of thread!");
[theConditionLock unlockWithCondition:UNLOCK];
}
-(void)display {
NSLog(#"I'm into display function");
while (YES) {
[theConditionLock lockWhenCondition:LOCK];
NSAutoreleasePool* pool1 = [[NSAutoreleasePool alloc]init];
NSLog(#"Into the lock");
[theConditionLock unlockWithCondition:UNLOCK];
[pool1 drain];
}
}
Both the insert and the display methods are called from the startThread.display is called before the calling of the insert method.But i want the display to wait till the insert finishes its execution.And if its stopped a signal has to be sent to the start thread to display the error message.
How to do it.
But in the code above the display method is called first and it continues in the infinite loop.

If you want to call insert before display simply move it above the call to start the thread.
m_bRunThread = YES;
[self insert];
if(m_bRunThread)
{
NSThread* myThread = [[NSThread alloc]initWithTarget:self selector:#selector(display) object:theConditionLock];
[myThread start];
}

you could try: performSelector:onThread:withObject:waitUntilDone: on self
From my understanding you want to sync the insert and display threads, such that display is called after insert (startThread), and report back to insert (startThread) (not sure if I got it right).
If I hot it right, something like this should do the trick (not tested, might need some small changes):
[self insert];
NSThread* myThread = [[NSThread alloc] init];
[self performSelector:#selector(display) onThread:myThread withObject:nil waitUntilDone:YES];
//myThread stopped, check its return status (maybe set some variables) and display error message
this would be another way:
m_bRunThread = YES;
[self insert];
if(m_bRunThread)
{
NSThread* myThread = [[NSThread alloc]initWithTarget:self selector:#selector(display) object:theConditionLock];
[myThread start];
}
while(m_bRunThread){//check if display is still running
[NSThread sleepForTimeInterval:0.5];
}
//display thread stopped

Related

Cocos2d How to create progress bar(loading scene)

how in order load music, images, and other stuff to scene with progress bar and move bar smooth..
i guess logic of progress bar is to create new thread - load data and destroy thread
here is my code to load stuff but it's not work, progress bar appears but not updating value
-(void)s1
{
[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:#"game_music.caf"];
}
-(void)s2
{
[[SimpleAudioEngine sharedEngine] preloadEffect:#"tap.caf"];
}
-(void)startThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
EAGLContext *context = [[[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES1
sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]] autorelease];
[EAGLContext setCurrentContext:context];
[self performSelector:#selector(loadBar)];
//[self schedule:#selector(tick:)];
[self performSelector:#selector(s1)]; // uploading file
[self performSelector:#selector(progressUpdateValue)]; // add 10 value to progress
[self performSelector:#selector(s2)]; // uploading file
[self performSelector:#selector(progressUpdateValue)]; // add 10 value to progress
[self performSelector:#selector(replaceScene)
onThread:[[CCDirector sharedDirector] runningThread]
withObject:nil
waitUntilDone:false];
[pool release];
}
-(void)replaceScene
{
[[CCDirector sharedDirector]replaceScene:[GameScene node]];
}
-(id)init
{
self = [super init];
if (self != nil)
{
[NSThread detachNewThreadSelector:#selector(startThread) toTarget:self withObject:nil];
}
return self;
}
Thanks in advance.
interface.. there you go..)
#interface LoadScene : CCScene
{
GPLoadingBar *loadingBar;
float value;
}
Ok, so you should load resources in background, while updating loadBar in main thread. For the SimpleAudioEngine you really need NSThread, but CCTextureCashe has -addImageAsync method which allow you to load images asynchronously without problems. So your code should look something like this:
-(void)s1
{
[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:#"game_music.caf"];
}
-(void)s2
{
[[SimpleAudioEngine sharedEngine] preloadEffect:#"tap.caf"];
}
-(void)startThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self s1];
loadingBar.value = 0.5;
[self s2];
[self performSelectorOnMainThread:#selector(replaceScene)
withObject:nil
waitUntilDone:false];
[pool release];
}
-(void)replaceScene
{
[[CCDirector sharedDirector]replaceScene:[GameScene node]];
}
-(id)init
{
self = [super init];
if (self != nil)
{
[self loadBar];
[NSThread detachNewThreadSelector:#selector(startThread) toTarget:self withObject:nil];
}
return self;
}
-(void) loadingFinished
{
[self replaceScene];
}
Cocos2d has its own updating loop, so you don't need to create your one for updating loadingBar. It also has a drawing loop, so if you want to dynamically update something on screen you should only set up values for update and not to stop main thread with loading resources
also, you could use [self s1] instead of [self performSelector:#selector(s1)] because they are identical. Hope that would help

How do I resolve this deadlock that happen ocassionally?

I have one managedObjectContext with concurency type of NSMainQueueConcurrencyType
+ (NSManagedObjectContext *)managedObjectContextMainThread
{
static NSManagedObjectContext *__managedObjectContext=nil;
#synchronized(self)
{
if (__managedObjectContext != nil)
{
}
else {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
}
}
return __managedObjectContext;
}
The main managedObjectContext is NEVER accessed outside of the main thread except when setting the other managedObjectContext.parent. So that mainManagedObjectContext is the parent for all threads.
Now when I run the program, sometimes it reach a deadlock. I pause the program and this is what I see:
As we see in the picture, there are 2 threads that seems to be in the deadlock. The first is the main thread.
It deadlock on #synchronize (self). Reasonable.
The other thread is deadlock on:
So it locks when trying to change the persistent store of the static variable that hold the __managedObjectContext.
Let me put the code again to reiterate:
+ (NSManagedObjectContext *)managedObjectContextMainThread
{
static NSManagedObjectContext *__managedObjectContext=nil;
#synchronized(self) //Main thread deadlock here
{
if (__managedObjectContext != nil)
{
}
else {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__managedObjectContext setPersistentStoreCoordinator:coordinator]; //Secondary thread dead lock here
}
}
}
return __managedObjectContext;
}
My question is why in the earth the [__managedObjectContext setPersistentStoreCoordinator:coordinator];
NOTHING else is accessing __managedObjectContext. The second thread (the non main one) is trying to set the __managedObjectContext as the parent context. The first thread is just waiting happily in #synchronized. It doesn't do anything.
So why the deadlock and how to solve that?
Oh the child managedObjectContext is created here:
#synchronized(self)
{
if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) {
NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
threadContext.parentContext = [self managedObjectContextMainThread]; //Stuck here. This goes straight to above function managedObjectContextMainThread where it stucks.
threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[managedObjectContexts setObject:threadContext forKey:[self threadKey]];
}
}
The problem is I tried to create the main managed object context on a thread different than the main thread.
For some reason it doesn't work.
I still love lazy loading. So all I need to do is to ensure that the main managedObjectContext is created on
the main thread
before any other managedObjectContexts are created.
I do not want to ensure that my program do not try to access the other managedObjectContexts first
So that looks like a job for dispatch_sync.
I then added this code:
dispatch_sync(dispatch_get_main_queue(),^{
[self managedObjectContextMainThread];//Access it once to make sure it's there
});
before I created all background child managedObjectContexts. That should be fast because once created the function will only return the static variable.
+(NSManagedObjectContext *)managedObjectContext {
NSThread *thread = [NSThread currentThread];
//BadgerNewAppDelegate *delegate = [BNUtilitiesQuick appDelegate];
//NSManagedObjectContext *moc = delegate.managedObjectContext;
if ([thread isMainThread]) {
//NSManagedObjectContext *moc = [self managedObjectContextMainThread];
return [self managedObjectContextMainThread];
}
else{
dispatch_sync(dispatch_get_main_queue(),^{
[self managedObjectContextMainThread];//Access it once to make sure it's there
});
}
// a key to cache the context for the given thread
NSMutableDictionary *managedObjectContexts =[self thread].managedObjectContexts;
#synchronized(self)
{
if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) {
NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
threadContext.parentContext = [self managedObjectContextMainThread];
//threadContext.persistentStoreCoordinator= [self persistentStoreCoordinator]; //moc.persistentStoreCoordinator;// [moc persistentStoreCoordinator];
threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[managedObjectContexts setObject:threadContext forKey:[self threadKey]];
}
}
return [managedObjectContexts objectForKey:[self threadKey]];
}

What is the meaning of using combination of detachNewThreadSelector:toTarget:withObject and [NSThread Start]

I am using below code where in method startThread if I am using detachNewThreadSelector method, it blocks my UI but when I use to make object of NSThread and call start method and in that I called run method it is not blocking my UI.
What I am not getting is detachNewThreadSelector will run in background so it should not block my UI.then why so in my case?
and what is with start method and NSThread object? will it run in background or main thread?
I have search so many articles and StackOverFlow questions but not get in which senario actually these Threads workout
-(void)startThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:#selector(run:) object:nil];
//[myThread start];
[NSThread detachNewThreadSelector:#selector(run:) toTarget:self withObject:nil];
[pool release];
}
-(void)run:(id)param
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (threadProgressView.progress < 1) {
[NSThread sleepForTimeInterval:0.25];
[self updateProgressBar];
//[NSThread detachNewThreadSelector:#selector(updateProgressBar) toTarget:self withObject:nil];
}
threadStartButton.hidden = NO;
[pool release];
}
-(void)updateProgressBar
{
NSLog(#"In update progress bar");
float actual = [threadProgressView progress];
threadValueLabel.text = [NSString stringWithFormat:#"%.2f",actual];
threadProgressView.progress = actual + 0.025;
}

Problem with UIImageView loading via OperationQueue

I load a UIImageView using an NSOperationQueue.
The load fetches an image from the Internet and then adds it to an image view. The problem I have is that the method finishes but it takes about 3 seconds later for the image view to actually either show the image or remove the image view from the superview...
- (void)viewDidLoad { NSLog(#"AirportDetailView: viewDidLoad");
[super viewDidLoad];
[self.activity startAnimating];
self.queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(loadImage) object:NULL];
[self.queue addOperation:operation];
[operation release];
}
-(void)loadImage {
[myAp ImageForAp];
NSLog(#"ImageFor Ap Ended, %#",myAp.ApDiagram);
[self.activity stopAnimating];
if (myAp.ApDiagram==NULL) {
NSLog(#"Finally Gets Here");
[self.Diagram removeFromSuperview];
}
else {
NSLog(#"Finally Gets Here with Diag");
[self.Diagram setBackgroundImage:myAp.ApDiagram forState:UIControlStateNormal];
}
}
The NSLOG shows a delay between the first two log statements of about 3 seconds can't understand why....
Updated with my Latest Code......
-(void)loadImage {
[myAp ImageForAp];
NSLog(#"ImageFor Ap Ended, %#",myAp.ApDiagram);
[self performSelectorOnMainThread:#selector(UpdateUI) withObject:nil waitUntilDone:NO];
}
-(void)UpdateUI {
[self.activity stopAnimating];
if (myAp.ApDiagram==NULL) {
NSLog(#"Finally Gets Here");
[self.Diagram removeFromSuperview];
}
else {
NSLog(#"Finally Gets Here with Diag");
[self.Diagram setBackgroundImage:myAp.ApDiagram forState:UIControlStateNormal];
}
}
Make sure that the loadImage method is being run on the main thread. All UI operations need to happen on the main thread to work as expected. Your code will need to look similar to this.
-(void)loadImage {
[myAp ImageForAp];
[self performSelectorOnMainThread:#selector(UpdateUI) withObject:nil waitUntilDone:NO];
}
-(void)UpdateUI {
[self.activity stopAnimating];
if (myAp.ApDiagram==NULL) {
[self.Diagram removeFromSuperview];
}
else {
[self.Diagram setBackgroundImage:myAp.ApDiagram forState:UIControlStateNormal];
}
}
There is also a possible memory leak inside of viewDidLoad.
self.queue = [NSOperationQueue new]; should be changed to
self.queue = [[[NSOperationQueue alloc] init] autorelease];

Activity Indicator doesn't spin

I'm trying to add a spinning activity indicator (UIActivityIndicatorView) to my app while it parses data from the internet. I have an IBOutlet (spinner) connected to a UIActivityIndicatorView in IB. Initially I had it set up like this:
-
(void) function {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[spinner startAnimating];
//parse data from internet
[spinner stopAnimating];}
But the spinner wouldn't spin. I read that it had something to do with everything being on the same thread. So I tried this:
- (void) newFunction {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[spinner startAnimating];
[NSThread detachNewThreadSelector: #selector(function) toTarget: self withObject: nil];
[spinner stopAnimating];}
But still no luck. Any ideas? Thanks.
Your newFunction: method should look like this:
- (void) newFunction {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[NSThread detachNewThreadSelector: #selector(function) toTarget: self withObject: nil];
}
And your function method should look like this:
- (void) function {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self.spinner performSelectorOnMainThread:#selector(startAnimating) withObject:nil waitUntilDone:NO];
//...
[self.spinner performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:NO];
[pool drain];
}
you should not intitialize indicator again .please replace your code with this.
-(void) function {
[spinner startAnimating];
[self performSelector:#selector(newfunction) withObject:nil afterDelay:3.0];
}
- (void) newfunction {
[spinner stopAnimating];
}
Thanks.
Just see that the "//parse data from internet " is synchronous or asynchronous. Asynchronous would mean that a separate thread would start from that point on, and the current function execution will continue without delay.
In your second example, you are explicitly making separate thread, which means that #selector(function) will happen on a separate thread, and the next statement [spinner stopAnimating] is executed immediately. So, it seems like spinner is not spinning at all.
Moreover, make sure you start and stop the activity indicator on main thread only.