iOS 多執行緒安全的陣列MultiThreadSafeObject

GabrielPanda發表於2018-01-24

iOS只提供了非執行緒安全的陣列。 如果要多執行緒併發的使用一個陣列物件就必須要加鎖,頻繁加鎖使程式碼的呼叫非常的麻煩。

我們需要多執行緒的讀寫鎖在類的內部實現,所以需要對NSMutableArray進行封裝,封裝後的物件負責接受所有事件並將其轉發給真正的NSMutableArray物件,並通過合理的排程使得其支援多執行緒併發。

新建一個物件來對NSMutableArray 陣列進行封裝,包含 dispatch_queue_t 排程佇列物件 和一個 NSObject 具體操作物件作為成員變數

@implementation MultiThreadSafeObject
- (id)init
{
    self = [super init];
    if (self)
    {
        _mtsDispatchQueue = dispatch_queue_create("COM.MTS.MultiThreadSafeObject", NULL);
    }
    return self;
}

- (void)dealloc
{
    _mtsDispatchQueue = nil;
    _mtsContainer = nil;
}
複製程式碼

我們再新建mtsMutableArray類繼承自MultiThreadSafeObject併為其宣告簡單介面來支援其作為Array使用

#import "MultiThreadSafeObject.h"

@protocol mtsMutableArrayProtocol

@optional
- (id)lastObject;
- (id)objectAtIndex:(NSUInteger)index;
- (NSUInteger)count;

- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;

@end

@interface mtsMutableArray : MultiThreadSafeObject<mtsMutableArrayProtocol>

@end
複製程式碼

使用訊息轉發

#pragma mark - public method
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    return [[_mtsContainer class] instanceMethodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSMethodSignature *sig = [anInvocation valueForKey:@"_signature"];
    
    const char *returnType = sig.methodReturnType;
    //NSLog(@"%@ = > %@",anInvocation.target, NSStringFromSelector(anInvocation.selector));
    //NSLog(@"%s",returnType);
    
    if (!strcmp(returnType, "v"))
    {
        //沒有返回值 setter方法 非同步barrier
        /** the setter method just use async dispatch
         remove the barrier to make it faster when u r sure that invacations will not affect each other
         */
        dispatch_barrier_async(_mtsDispatchQueue, ^{
            [anInvocation invokeWithTarget:_mtsContainer];
        });
    }
    else
    {
        //有返回值 getter方法 同步barrier
        /** all getter method need sync dispatch
         barrier make sure the result is correct
         getter method need barrier in most ways unless u dont except this */
        
        dispatch_barrier_sync(_mtsDispatchQueue, ^{
            [anInvocation invokeWithTarget:_mtsContainer];
        });
    }
}
複製程式碼

獲取排程方法的返回值,如果是void型方法則使用非同步排程,如果是getter型別的則使用同步排程,可以略微的提升效能。

可以通過繼承等方法為不同型別的container指定不同的排程規則以確保在邏輯正常的情況下擁有最高的效能。

程式碼

相關文章