Question

Environment: Mac OS X 10.9, Xcode 5.0.2, ARC disabled.

Question: How free memory of property after all thread finish job. See example below.

I`am create mini example with one button “(IBAction)btnRun:(id)sender”. Example read txt file and fill NSArray property (sharedListWords). Then run two thread and each thread display words,
see OUT Section. When threads finished a job, property (self.sharedListWords) not released! But I want free memory which allocated for (self.sharedListWords) property. The action “btnRun” exit before threads finished job and I cant release (self.sharedListWords) in this action.

How free memory of property (self.sharedListWords) after threads finish job? Yes good answer here by create dependency operation jobFinished(), but how correct release property?

And this is my first multithreading program on Objective-c, I will be glad for adjustments.


AppDelegate.h:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
{
    volatile int32_t sharedIndex;   // Shared between threads, current index in array
    NSOperationQueue* operationQueue;
}
@property (assign) IBOutlet NSWindow *window;
// Shared between threads, list of words
@property (atomic, retain) NSArray* sharedListWords;
- (void)worker;

@end

AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

- (IBAction)btnRun:(id)sender
{
    // Read txt file dictionary of words, where is each words in new line.
    NSString* dictionaryFilePath = [NSString stringWithFormat:@"/Users/admin/dictionary.txt"];
    NSString* fileContents = [NSString stringWithContentsOfFile:dictionaryFilePath
                                                       encoding:NSUTF8StringEncoding error:nil];
    // Get array of string separated by new line
    self.sharedListWords = [fileContents componentsSeparatedByCharactersInSet:
                                [NSCharacterSet newlineCharacterSet]];

    //self.sharedListWords = @[@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eight",@"nine",@"ten"];

    self->sharedIndex = -1;

    int numberOfThreads = 2;

    // Run method working() in separate threads
    for(int i=0; i<numberOfThreads; ++i)
    {
        //////////////////////////////////////////
        // Create a thread
        // Create new NSOperatin object with function puting in @selector() for run in other thread.
        NSOperation* startBruteOper = [[NSInvocationOperation alloc]
                                       initWithTarget:self selector:@selector(worker) object:nil];
        // Add the operation to the queue and let it to be executed.
        [operationQueue addOperation:startBruteOper];
        [startBruteOper release];
        /////////////////////////////////////////
    }
}

- (void)worker
{
    unsigned long countWords = [self.sharedListWords count];

    int32_t index = 0;

    // Use atomic operation for thread safe
    while( (index = OSAtomicIncrement32( &(self->sharedIndex) ) ) < countWords )
    {
        NSLog(@"[%@] working on \"%@\"",
              [NSThread currentThread],
              [self.sharedListWords objectAtIndex:index]);
    }

    NSLog(@"[%@] work is finish.", [NSThread currentThread]);
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Multithreading queue list
    operationQueue = [[NSOperationQueue alloc] init];
}

@end

OUT Section:

[<NSThread: num = 2}] working on "one"
[<NSThread: num = 3}] working on "two"
[<NSThread: num = 2}] working on "three"
[<NSThread: num = 3}] working on "four"
[<NSThread: num = 2}] working on "five"
[<NSThread: num = 3}] working on "six"
[<NSThread: num = 2}] working on "seven"
[<NSThread: num = 3}] working on "eight"
[<NSThread: num = 2}] working on "nine"
[<NSThread: num = 3}] working on "ten"
[<NSThread: num = 2}] work is finish.
[<NSThread: num = 3}] work is finish.
Was it helpful?

Solution 2

You can add another operation which is dependent on all "worker" operations, as described in

That operation is run after all its dependencies have finished, so you can call

self.sharedListWords = nil;

in the finished operation to release the array.

OTHER TIPS

This is correct code, after Martins instructions.

AppDelegate.h:

    #import <Cocoa/Cocoa.h>

    @interface AppDelegate : NSObject <NSApplicationDelegate>
    {
        volatile int32_t sharedIndex;   // Shared between threads, current index in array
        NSOperationQueue* operationQueue;
    }
    @property (assign) IBOutlet NSWindow *window;
    // Shared between threads, list of words
    @property (atomic, retain) NSArray* sharedListWords;
    - (void)worker;

    @end

AppDelegate.m:

    #import "AppDelegate.h"

    @implementation AppDelegate

    - (IBAction)btnRun:(id)sender
    {
        // Read txt file dictionary of words, where is each words in new line.
        NSString* dictionaryFilePath = [NSString stringWithFormat:@"/Users/admin/dictionary.txt"];
        NSString* fileContents = [NSString stringWithContentsOfFile:dictionaryFilePath
                                                           encoding:NSUTF8StringEncoding error:nil];
        // Get array of string separated by new line
        self.sharedListWords = [fileContents componentsSeparatedByCharactersInSet:
                                    [NSCharacterSet newlineCharacterSet]];

        //self.sharedListWords = @[@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eight",@"nine",@"ten"];

        self->sharedIndex = -1;

        int numberOfThreads = 2;

        NSOperation* jobFinishedOper = [[NSInvocationOperation alloc]
                                    initWithTarget:self selector:@selector(jobFinished) object:nil];

        // Run method working() in separate threads
        for(int i=0; i<numberOfThreads; ++i)
        {
            //////////////////////////////////////////
            // Create a thread
            // Create new NSOperatin object with function puting in @selector() for run in other thread.
            NSOperation* startBruteOper = [[NSInvocationOperation alloc]
                                           initWithTarget:self selector:@selector(worker) object:nil];
            // Add the operation to the queue and let it to be executed.
            [operationQueue addOperation:startBruteOper];
            [jobFinishedOper addDependency:startBruteOper]; // 'jobFinishedOper' run only when 'startBruteOper' finished!
            [startBruteOper release];
            /////////////////////////////////////////
        }
        // 'jobFinishedOper' run only when all prevous operation is finished!
        [operationQueue addOperation:jobFinishedOper];
        [jobFinishedOper release];
    }

    - (void)worker
    {
        unsigned long countWords = [self.sharedListWords count];

        int32_t index = 0;

        // Use atomic operation for thread safe
        while( (index = OSAtomicIncrement32( &(self->sharedIndex) ) ) < countWords )
        {
            NSLog(@"[%@] working on \"%@\"",
                  [NSThread currentThread],
                  [self.sharedListWords objectAtIndex:index]);
        }

        NSLog(@"[%@] work is finish.", [NSThread currentThread]);
    }

    - (void)jobFinished
    {
        self.sharedListWords = nil;
    }

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
        // Multithreading queue list
        operationQueue = [[NSOperationQueue alloc] init];
    }

    @end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top