我在執行緒中運行一些 Metal 代碼,但遇到了一些我不完全理解的問題。USE_THREAD 0使用和運行以下代碼USE_AUTORELEASEPOOL 0作業正常,但將其中之一設定為 1 會導致 SIGSEGV in objc_release:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x20)
* frame #0: 0x00007fff2020d4af libobjc.A.dylib`objc_release 31
frame #1: 0x00007fff2022b20f libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) 167
frame #2: 0x00007fff2020de30 libobjc.A.dylib`objc_autoreleasePoolPop 161
frame #3: 0x0000000100003d60 a.out`render(void*) 896
frame #4: 0x0000000100003dd8 a.out`main 24
frame #5: 0x00007fff20388f3d libdyld.dylib`start 1
frame #6: 0x00007fff20388f3d libdyld.dylib`start 1
使用 autoreleasepool 我可以理解,因為物件已經被釋放(因為release在它們上手動呼叫),但是為什么當代碼在執行緒內運行時會出現同樣的問題?這與pthreads具體有關嗎?我缺少的地方是否有“隱藏的”自動釋放池?
我知道使用自動釋放池而不是手動釋放會達到相同的結果,但我想了解這里發生了什么。
// clang main.mm -lobjc -framework Metal
#define USE_THREAD 0
#define USE_AUTORELEASEPOOL 1
#import <Metal/Metal.h>
void * render(void *) {
#if USE_AUTORELEASEPOOL
@autoreleasepool {
#else
{
#endif
NSArray<id<MTLDevice>> * devices = MTLCopyAllDevices();
id<MTLDevice> device = devices[0];
id<MTLCommandQueue> command_queue = [device newCommandQueue];
MTLTextureDescriptor * texture_descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm width:640 height:480 mipmapped:NO];
texture_descriptor.usage = MTLTextureUsageRenderTarget;
id<MTLTexture> texture = [device newTextureWithDescriptor:texture_descriptor];
[texture_descriptor release];
texture_descriptor = NULL;
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
MTLRenderPassDescriptor * render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
render_pass_descriptor.colorAttachments[0].texture = texture;
id<MTLRenderCommandEncoder> render_command_encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
[render_pass_descriptor release];
render_pass_descriptor = NULL;
[render_command_encoder endEncoding];
[render_command_encoder release];
render_command_encoder = nil;
[command_buffer commit];
[command_buffer waitUntilCompleted];
[command_buffer release];
command_buffer = nil;
[texture release];
texture = nil;
[command_queue release];
command_queue = nil;
}
return 0;
}
#include <pthread.h>
int main() {
#if USE_THREAD
pthread_t thread;
pthread_create(&thread, NULL, render, NULL);
pthread_join(thread, NULL);
#else
render(NULL);
#endif
return 0;
}
uj5u.com熱心網友回復:
我不確定 Apple 是否更新過關于此行為的檔案,但大約從 macOS 10.7 開始,所有 POSIX 執行緒都自動填充了自動釋放池塊。dealloc您可以從自動釋放的物件中清楚地看到它:
#import <Foundation/Foundation.h>
#import <pthread.h>
@interface TDWObject : NSObject
@end
@implementation TDWObject
- (void)dealloc {
[super dealloc];
NSLog(@"%@", [NSThread callStackSymbols]);
}
@end
void *run(void *objPtr) {
TDWObject *obj = (__bridge TDWObject *)objPtr;
[obj autorelease];
return NULL;
}
int main() {
pthread_t thread;
TDWObject *obj = [TDWObject new];
pthread_create(&thread, NULL, run, (__bridge void *)obj);
pthread_join(thread, NULL);
return 0;
}
此代碼(使用 MRC 編譯時)將列印以下堆疊跟蹤:
-[TDWObject dealloc] 83
_ZN19AutoreleasePoolPage12releaseUntilEPP11objc_object 168
objc_autoreleasePoolPop 227
_ZN20objc_tls_direct_baseIP19AutoreleasePoolPageL7tls_key3ENS0_14HotPageDeallocEE5dtor_EPv 140
_pthread_tsd_cleanup 607
_pthread_exit 70
_pthread_start 136
thread_start 15
objc_autoreleasePoolPop函式正是如今在自動釋放池塊末尾呼叫的函式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/537572.html
