Norton Commander
Norton Commander

Reputation: 683

Why isn't multithreading working in this implementation?

Q1: Can I call a method and have it execute on a background thread from inside another method that is currently executing on the main thread?

Q2: As an extension of the above, can I call a method and have it execute on a background thread from inside another method that is currently executing on some other background thread itself?

Q3: And one final question given the above : if I initialize an instance of some object X on some thread (main/background) and then have a method Y, of that object X, executing on some other background thread, can this method Y send messages and update an int property (e.g. of that Object X, or is such communication not possible ?

The reason I'm asking this last question is because I've been going over and over it again and I can't figure what is wrong here:

The following code returns zero acceleration and zero degrees values :

MotionHandler.m

@implementation MotionHandler

@synthesize currentAccelerationOnYaxis; // this is a double

-(void)startCompassUpdates
{
    locationManager=[[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    locationManager.delegate=self;
    [locationManager startUpdatingHeading];
    NSLog(@"compass updates initialized");
}

-(int) currentDegrees
{
    return (int)locationManager.heading.magneticHeading;
}
-(void) startAccelerationUpdates
{
    CMMotionManager *motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 0.01;
    [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
                                       withHandler:^(CMDeviceMotion *motion, NSError *error)
                                       {
                                           self.currentAccelerationOnYaxis = motion.userAcceleration.y;
                                       }
    ];
}

@end

Tester.m

@implementation Tester

-(void)test
{
    MotionHandler *currentMotionHandler = [[MotionHandler alloc] init];

    [currentMotionHandler performSelectorInBackground:@selector(startCompassUpdates) withObject:nil];

    [currentMotionHandler performSelectorInBackground:@selector(startAccelerationUpdates) withObject:nil];

    while(1==1)
    {
        NSLog(@"current acceleration is %f", currentMotionHandler.currentAccelerationOnYaxis);
        NSLog(@"current degrees are %i", [currentMotionHandler currentDegrees]);
    }

SomeViewController.m

@implementation SomeViewController
-(void) viewDidLoad
{
    [myTester performSelectorInBackground:@selector(test) withObject:nil];
}
@end

However, the following code returns those values normally :

Tester.m

@interface Tester()
{
    CLLocationManager *locationManager;
    double accelerationOnYaxis;
    // more code..
}
@end

@implementation Tester

- (id) init
{
    locationManager=[[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    locationManager.delegate=self;
    [locationManager startUpdatingHeading];

    // more code..
}


-(void) test
{
    CMMotionManager *motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 0.01;
    [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
                                       withHandler:^(CMDeviceMotion *motion, NSError *error)
     {
         accelerationOnYaxis = motion.userAcceleration.y;
     }
     ];

     while(1==1)
    {
        NSLog(@"current acceleration is %f", accelerationOnYaxis);
        NSLog(@"current degrees are %i", locationManager.heading.magneticHeading);
    }
}

SomeViewController.m

@implementation SomeViewController

-(void) viewDidLoad
{
    [myTester performSelectorInBackground:@selector(test) withObject:nil];
}

What's wrong with the first version? I really want to use that first one because it seems much better design-wise.. Thank you for any help!

Upvotes: 0

Views: 236

Answers (2)

Robin van Dijke
Robin van Dijke

Reputation: 752

You should take a look at the Grand Central Dispatch documentation from Apple. It allows you to use multiple threads in a block-based structure.

2 importants function are dispatch_sync() and dispatch_async().

Some examples:

To execute a certain block of code on a background thread and wait until it is finished:

__block id someVariable = nil;
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // do some heavy work in the background

    someVariable = [[NSObject alloc] init];
});

NSLog(@"Variable: %@", someVariable);

This function modifies the variable someVariable which you can use later on. Please note that the main thread will be paused to wait for the background thread. If that is not what you want, you can use dispatch_async() as follows:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // do some heavy work in the background

    NSObject *someVariable = [[NSObject alloc] init];

    // notify main thread that the work is done
    dispatch_async(dispatch_get_main_queue(), ^{
        // call some function and pass someVariable to it, it will be called on the main thread
        NSLog(@"Variable: %@", someVariable);
    });
});

Upvotes: 1

jtomschroeder
jtomschroeder

Reputation: 1054

Calling performSelectorInBackground:withObject: is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters (Threading Programming Guide). No matter where you call it, a new thread will be created to perform that selector. So to answer your first two questions: yes and yes.

For your final question, as long as this Object X is the same object in both methods, any of X's properties can be updated. But, beware that this can yield unexpected results (ie. see Concurrency Programming Guide). If multiple methods are updating X's property, values can be overwritten or disregarded. But, if you are only updating it from method Y and reading it from all other methods, such problems shouldn't occur.

Upvotes: 1

Related Questions