【问题标题】:Property, Threads, Memory management and Rock & Roll属性、线程、内存管理和摇滚
【发布时间】:2014-05-01 17:04:40
【问题描述】:

环境:Mac OS X 10.9、Xcode 5.0.2、ARC 已禁用。

问题:所有线程完成工作后如何释放属性内存。请参阅下面的示例。

我正在用一个按钮“(IBAction)btnRun:(id)sender”创建迷你示例。 示例读取 txt 文件并填充 NSArray 属性(sharedListWords)。然后运行两个线程,每个线程显示单词,
OUT部分。当线程完成工作时,属性(self.sharedListWords)没有释放!但我想要为 (self.sharedListWords) 属性分配的空闲内存。动作“btnRun”在线程完成作业之前退出,我无法在此动作中释放(self.sharedListWords)。

线程完成工作后如何释放属性(self.sharedListWords)的内存?是的好答案here通过创建依赖操作jobFinished(),但是如何正确释放属性?强>

这是我在 Objective-c 上的第一个多线程程序,我会很高兴进行调整。


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 部分

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

【问题讨论】:

  • Martin R> 我可以运行 [self.sharedListWords release];在处理程序 NSOperationQueue 中完成?
  • 我正在测试几分钟)
  • Martin R> 我正在让依赖处理程序 jobFinished() 查看更新的代码,第一次它工作正常,但是当我按下第二次按钮时,它在属性 self.sharedListWords 上返回分段错误。也许财产需要不同的释放?
  • 我已经习惯了 ARC,以至于我几乎不记得 MRC 时间了 :-) 但我认为你应该在 jobFinished 中分配 self.sharedListWords = nil,而不是调用 release

标签: ios objective-c multithreading memory-management


【解决方案1】:

这是正确的代码,根据 Martins 的指示。

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

【讨论】:

    【解决方案2】:

    您可以添加另一个依赖所有“worker”操作的操作,如 描述于

    该操作在其所有依赖项完成后运行,因此您可以调用

    self.sharedListWords = nil;
    

    在操作完成后释放数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2018-06-19
      相关资源
      最近更新 更多