Created
April 16, 2023 07:01
-
-
Save TheDreamsWind/49bc1d11817828d627d3968364b08d5e to your computer and use it in GitHub Desktop.
[SO-a/75344837/5690248] An operation class with an arbitrary thread stack size
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TDWOperation.h | |
// | |
// Created by Aleksandr Medvedev on 16.04.2023. | |
// | |
#import <Foundation/Foundation.h> | |
NS_ASSUME_NONNULL_BEGIN | |
typedef void(^TDWOperationBlock)(void); | |
__attribute__((__objc_direct_members__)) | |
@interface TDWOperation: NSOperation | |
@property (assign, nonatomic, readonly) size_t stackSize; // bytes | |
@property (copy, nonatomic) TDWOperationBlock executionBlock; | |
- (instancetype)initWithExecutionBlock:(TDWOperationBlock)block | |
stackSize:(size_t)stackSize /* bytes */ NS_DESIGNATED_INITIALIZER; | |
@end | |
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TDWOperation.m | |
// | |
// Created by Aleksandr Medvedev on 16.04.2023. | |
// | |
#import "TDWOperation.h" | |
#import <pthread.h> | |
#define EXECUTE_WITH_ERROR(codeVar, execution) if((codeVar = execution)) {\ | |
NSLog(@"Failed to execute " #execution " with error code: %d", codeVar);\ | |
return;\ | |
} | |
NS_ASSUME_NONNULL_BEGIN | |
__attribute__((__objc_direct_members__)) | |
@interface TDWOperation () | |
@property (assign, getter=tdw_p_isThreadStarted, setter=tdw_p_setThreadStarted:) BOOL tdw_p_threadStarted; | |
@property (assign, nonatomic) pthread_t tdw_p_underlyingThread; | |
@property (strong, nonatomic, readonly) dispatch_queue_t tdw_p_threadStartedSyncQueue; | |
@end | |
NS_ASSUME_NONNULL_END | |
@implementation TDWOperation | |
@synthesize tdw_p_threadStarted = _tdw_p_threadStarted; | |
#pragma mark Lifecycle | |
- (instancetype)initWithExecutionBlock:(TDWOperationBlock)block | |
stackSize:(size_t)stackSize { | |
if (self = [super init]) { | |
_stackSize = stackSize; | |
_executionBlock = block; | |
_tdw_p_threadStarted = NO; | |
_tdw_p_threadStartedSyncQueue = dispatch_queue_create("the.dreams.wind.property_access.TDWOperation.isThreadStarted", | |
DISPATCH_QUEUE_CONCURRENT); | |
} | |
return self; | |
} | |
- (instancetype)init { | |
return [self initWithExecutionBlock:^{} stackSize:1024 * 1024 * 512]; | |
} | |
#pragma mark NSOperation | |
- (void)main { | |
pthread_attr_t attrs; | |
int statusCode; | |
EXECUTE_WITH_ERROR(statusCode, pthread_attr_init(&attrs)) | |
// Allocates 32 MiB stack size | |
EXECUTE_WITH_ERROR(statusCode, pthread_attr_setstacksize(&attrs, _stackSize)) | |
pthread_t thread; | |
EXECUTE_WITH_ERROR(statusCode, pthread_create(&thread, &attrs, &tdw_p_runExecutionBlock, (__bridge_retained void *)self)) | |
EXECUTE_WITH_ERROR(statusCode, pthread_attr_destroy(&attrs)) | |
void* result = NULL; | |
if (!self.cancelled) { | |
self.tdw_p_threadStarted = YES; | |
EXECUTE_WITH_ERROR(statusCode, pthread_join(thread, &result)); | |
self.tdw_p_threadStarted = NO; | |
} | |
NSLog(@"Main is finished with result: %d", *(int *)result); | |
free((int *)result); | |
} | |
#pragma mark Properties | |
- (void)setExecutionBlock:(TDWOperationBlock)executionBlock { | |
if (self.tdw_p_isThreadStarted) { | |
[NSException raise:NSInternalInconsistencyException | |
format:@"Cannot change execution block when execution is already started"]; | |
} | |
_executionBlock = executionBlock; | |
} | |
- (BOOL)tdw_p_isThreadStarted { | |
__block BOOL result; | |
dispatch_sync(_tdw_p_threadStartedSyncQueue, ^{ | |
result = _tdw_p_threadStarted; | |
}); | |
return result; | |
} | |
- (void)tdw_p_setThreadStarted:(BOOL)threadStarted { | |
dispatch_barrier_async(_tdw_p_threadStartedSyncQueue, ^{ | |
self->_tdw_p_threadStarted = threadStarted; | |
}); | |
} | |
#pragma mark Private | |
void *tdw_p_runExecutionBlock(void *args) { | |
TDWOperation *self = (__bridge_transfer TDWOperation *)args; | |
if (self.executionBlock) { | |
self.executionBlock(); | |
} | |
// Status code | |
int *result = calloc(1, sizeof(int)); | |
return result; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment