gpt4 book ai didi

ios - 从 Objective-C block 中修改存储在实例变量中的信号量

转载 作者:可可西里 更新时间:2023-11-01 05:32:20 27 4
gpt4 key购买 nike

Apple 提供 CPU and GPU Synchronization展示如何在 CPU 和 GPU 之间同步访问共享资源的示例项目。为此,它使用存储在实例变量中的信号量:

@implementation AAPLRenderer
{
dispatch_semaphore_t _inFlightSemaphore;
// other ivars
}

然后在另一个方法中定义此信号量:

- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
{
self = [super init];
if(self)
{
_device = mtkView.device;

_inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight);

// further initializations
}

return self;
}

MaxBuffersInFlight 定义如下:

// The max number of command buffers in flight
static const NSUInteger MaxBuffersInFlight = 3;

最后,信号量的使用如下:

/// Called whenever the view needs to render
- (void)drawInMTKView:(nonnull MTKView *)view
{
// Wait to ensure only MaxBuffersInFlight number of frames are getting processed
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER);

// Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight
_currentBuffer = (_currentBuffer + 1) % MaxBuffersInFlight;

// Update data in our buffers
[self updateState];

// Create a new command buffer for each render pass to the current drawable
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = @"MyCommand";

// Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully
// finished processing the commands we're encoding this frame. This indicates when the
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
// corrupting the rendering.
__block dispatch_semaphore_t block_sema = _inFlightSemaphore;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(block_sema);
}];

// rest of the method
}

我在这里没能理解的是这条线的必要性

__block dispatch_semaphore_t block_sema = _inFlightSemaphore;

为什么我要将实例变量复制到一个局部变量中,并用__block标记这个局部变量。如果我只是删除那个局部变量,而是写

[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(_inFlightSemaphore);
}];

似乎 也能正常工作。我还尝试用 __block 标记实例变量,如下所示:

__block dispatch_semaphore_t _bufferAccessSemaphore;

这用 Clang 编译,似乎也能正常工作。但是因为这是为了防止竞争条件,所以我想确定它有效。

所以问题是为什么 Apple 会创建标有 __block 的本地信号量副本?是否真的有必要,或者直接访问实例变量的方法是否同样有效?

作为旁注,this 的答案SO 问题评论说无法使用 __block 标记实例变量。答案是根据 gcc,但如果不应该这样做,为什么 Clang 会允许这样做?

最佳答案

这里重要的语义区别是,当您直接在 block 中使用 ivar 时,该 block 将对 self 进行强引用。通过创建一个引用信号量的局部变量,只有信号量被 block 捕获(通过引用),而不是 self,从而减少了保留循环的可能性。

至于 __block 限定符,您通常会使用它来指示局部变量在引用 block 中应该是可变的。但是,由于信号量变量 不会因调用signal 而发生变化,因此限定符在这里并不是绝对必要的。不过,从样式的角度来看,它仍然有一个有用的目的,因为它强调了变量的生命周期和用途。

关于为什么一个ivar可以用__block限定的话题,

why would Clang allow this if it shouldn't be done?

也许正是因为在 block 中捕获一个 ivar 意味着强烈捕获 self。无论是否使用 __block 限定符,如果您在 block 中使用 ivar,您都可能面临保留循环的风险,因此使用限定符不会产生额外的风险。最好使用局部变量(顺便说一句,它可以是对 self__weak 引用,就像 __block 限定引用一样容易到 ivar) 是明确和安全的。

关于ios - 从 Objective-C block 中修改存储在实例变量中的信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55244935/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com