我正在处理一些未在主线程上完成的音频处理。我的后台线程重复生成浮点数组,我的主线程将用它来向用户显示内容。这是线程安全还是过于简单?由于这是在OpenGL循环中,我想避免阻塞具有atomic
锁定的任一线程。
我对存储格式很灵活。 (C数组,NSArray等,双,CGFloat,NSNumber等)
请注意,每次调用第二个方法时,它都可能有也可能没有要处理的实际新数据。它只是想要最新的东西。
@interface
@property (nonatomic, strong) NSMutableArray *generatedNumbers;
@property (nonatomic, strong) NSArray *passedNumbers;
...
@end
@implementation
//This is called over and over repeatedly and an unpredictable rate
- (void) generateSomeNumbers{
...
[self.generatedNumbers removeAllObjects];
for (Something x in something){
...
[self.generatedNumbers addObject:someNSNumberOrCGFloat];
}
}
//This is called from the main thread (opengl CADisplayLink)
- (void) doStuffWithLatestGeneratedNumbers{
self.passedNumbers = [NSArray arrayWithArray:self.generatedNumbers];
[self doStuffWithNumbers:self.passedNumbers];
}
或者这个怎么样?:
@interface
@property (nonatomic, strong) NSMutableArray *generatedNumbers;
@property (nonatomic, strong) NSArray *passedNumbers;
...
@end
@implementation
//This is called over and over repeatedly and an unpredictable rate
- (void) generateSomeNumbers{
...
[self.generatedNumbers removeAllObjects];
for (Something x in something){
...
[self.generatedNumbers addObject:someNSNumberOrCGFloat];
}
[self copyNumbers:self.generatedNumbers];
}
- (void)copyNumbers:(NSArray *)numbers
{
@autoreleasepool
{
dispatch_async(dispatch_get_main_queue(), ^{
self.passedNumbers = [NSArray arrayWithArray:self.generatedNumbers];
});
}
}
//This is called from the main thread (opengl CADisplayLink)
- (void) doStuffWithLatestGeneratedNumbers{
[self doStuffWithNumbers:self.passedNumbers];
}
答案 0 :(得分:1)
由于这是在OpenGL循环中,我想避免阻塞 原子锁的线程
这使事情变得更加艰难。除非交换数组值的操作是原子操作(即单个CPU指令),否则您需要进行某种锁定。
如果您处理的值大于CPU的本机指令大小,则分配替换的操作将不是原子操作。
分配NSMutableArray指针是原子,但除非你乐意泄漏它正在替换的数组,否则你需要释放现有的数组。这两个操作的组合不是原子操作,因此需要使用锁保护(这是将属性标记为atomic
)。
我建议仔细检查一下你不能锁定。 The lock in question is a spin-lock protecting two instructions,所以即使在竞争时它也会非常便宜。如果您正在使用Objective-C,或者从堆中分配任何内存,那么您可能已经在过高的抽象级别工作以担心这种细节(做任何事情都涉及到锁定)。
要避免使用Objective-C或甚至分配内存来获取锁定的情况的示例是实时自动处理。由于锁定的持续时间不是完全可预测的,并且实时音频线程具有非常紧密的期限(比OpenGL环路更紧密 - 有时小于1ms,任何超限导致可听到的毛刺),它们无法安全使用。然后,在线程之间传递数据的标准方法是circular buffer。
答案 1 :(得分:0)
我就是这样做的:
@property (strong) NSArray* generatedNumbers;
....
- (void) generateSomeNumbers{
NSMutableArray* tempNumbers = [[NSMutableArray alloc] init];
for (Something x in something){
...
[tempNumbers addObject:someNSNumberOrCGFloat];
}
[self setGeneratedNumbers: tempNumbers];
}
//This is called from the main thread (opengl CADisplayLink)
- (void) doStuffWithLatestGeneratedNumbers{
[self doStuffWithNumbers: [self generatedNumbers]];
}
以上假设generatedNumbers
在generateNumbers中赋值后并未发生变异,我们也使用ARC。
请注意,该属性是原子的。我认为这是必要的,以阻止潜在的竞争条件,其中主线程试图获得generatedNumbers
但该数组在其有机会进行保留之前被另一个线程释放。