0

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.

Kevin
  • 1,469
  • 2
  • 19
  • 28
  • try to put log above your if condition.....and see if control is cumming there and where are you setting the `bool_run_progress_thread = YES;` – Inder Kumar Rathore May 17 '12 at 10:45
  • I've put an NSLog inside the method m_run_thread and I am only getting it to show once. Isn't the point of a thread to be running at all times? THanks. – Kevin May 17 '12 at 10:48
  • This method will run once..it won't run again and again..And it's wrong that thread to be running all the time. it finishes when task is over – Inder Kumar Rathore May 17 '12 at 10:51
  • I think you are calling this method with UI Element init method, you won't call thread there, all the UI stuff always done on main thread. – rishi May 17 '12 at 10:52

1 Answers1

2

"...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.

Dirk
  • 30,623
  • 8
  • 82
  • 102