深入理解dispatch_queue[举例子讲原理]-2

转自:https://github.com/mikeash/MADispatchQueue/tree/master/MADispatch


MADispatchQueue.h

//
//  MADispatchQueue.h
//  MADispatch
//
//  Created by Michael Ash on 8/31/15.
//  Copyright © 2015 mikeash. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MADispatchQueue : NSObject

+ (MADispatchQueue *)globalQueue;

- (id)initSerial: (BOOL)serial;

- (void)dispatchAsync: (dispatch_block_t)block;
- (void)dispatchSync: (dispatch_block_t)block;

@end

MADispatchQueue.m

//
//  MADispatchQueue.m
//  MADispatch
//
//  Created by Michael Ash on 8/31/15.
//  Copyright © 2015 mikeash. All rights reserved.
//

#import "MADispatchQueue.h"

#import "MAThreadPool.h"


@implementation MADispatchQueue {
    NSLock *_lock;
    NSMutableArray *_pendingBlocks;
    BOOL _serial;
    BOOL _serialRunning;
}

static MADispatchQueue *gGlobalQueue;
static MAThreadPool *gThreadPool;

+ (void)initialize {
    if(self == [MADispatchQueue class]) {
        gGlobalQueue = [[MADispatchQueue alloc] initSerial: NO];
        gThreadPool = [[MAThreadPool alloc] init];
    }
}

+ (MADispatchQueue *)globalQueue {
    return gGlobalQueue;
}

- (id)initSerial: (BOOL)serial {
    if ((self = [super init])) {
        _lock = [[NSLock alloc] init];
        _pendingBlocks = [[NSMutableArray alloc] init];
        _serial = serial;
    }
    return self;
}

- (void)dispatchAsync: (dispatch_block_t)block {
    [_lock lock];
    [_pendingBlocks addObject: block];
    
    if(_serial && !_serialRunning) {
        _serialRunning = YES;
        [self dispatchOneBlock];
    } else if (!_serial) {
        [self dispatchOneBlock];
    }
    
    [_lock unlock];
}

- (void)dispatchSync: (dispatch_block_t)block {
    NSCondition *condition = [[NSCondition alloc] init];
    __block BOOL done = NO;
    [self dispatchAsync: ^{
        block();
        [condition lock];
        done = YES;
        [condition signal];
        [condition unlock];
    }];
    [condition lock];
    while (!done) {
        [condition wait];
    }
    [condition unlock];
}

- (void)dispatchOneBlock {
    [gThreadPool addBlock: ^{
        [_lock lock];
        dispatch_block_t block = [_pendingBlocks firstObject];
        [_pendingBlocks removeObjectAtIndex: 0];
        [_lock unlock];
        
        block();
        
        if(_serial) {
            [_lock lock];
            if([_pendingBlocks count] > 0) {
                [self dispatchOneBlock];
            } else {
                _serialRunning = NO;
            }
            [_lock unlock];
        }
    }];
}

@end

MAThreadPool.h

//
//  MAThreadPool.h
//  MADispatch
//
//  Created by Michael Ash on 8/31/15.
//  Copyright © 2015 mikeash. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MAThreadPool : NSObject

- (void)addBlock: (dispatch_block_t)block;

@end

MAThreadPool.m

//
//  MAThreadPool.m
//  MADispatch
//
//  Created by Michael Ash on 8/31/15.
//  Copyright © 2015 mikeash. All rights reserved.
//

#import "MAThreadPool.h"


@implementation MAThreadPool {
    NSCondition *_lock;
    
    NSUInteger _threadCount;
    NSUInteger _activeThreadCount;
    NSUInteger _threadCountLimit;
    
    NSMutableArray *_blocks;
}

- (id)init {
    if((self = [super init])) {
        _lock = [[NSCondition alloc] init];
        _blocks = [[NSMutableArray alloc] init];
        _threadCountLimit = 128;
    }
    return self;
}

- (void)addBlock: (dispatch_block_t)block {
    [_lock lock];
    
    [_blocks addObject: block];
    
    NSUInteger idleThreads = _threadCount - _activeThreadCount;
    if([_blocks count] > idleThreads && _threadCount < _threadCountLimit) {
        [NSThread detachNewThreadSelector: @selector(workerThreadLoop:) toTarget: self withObject: nil];
        _threadCount++;
    }
    
    [_lock signal];
    [_lock unlock];
}

- (void)workerThreadLoop: (id)ignore {
    [_lock lock];
    while(1) {
        while([_blocks count] == 0) {
            [_lock wait];
        }
        dispatch_block_t block = [_blocks firstObject];
        [_blocks removeObjectAtIndex: 0];
        _activeThreadCount++;
        [_lock unlock];
        
        block();
        
        [_lock lock];
        _activeThreadCount--;
    }
}

@end

main.m

//
//  main.m
//  MADispatch
//
//  Created by Michael Ash on 8/31/15.
//  Copyright © 2015 mikeash. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "MADispatchQueue.h"


int testHarness__totalFailures = 0;

#define TEST(name, code) do { \
        NSLog(@"Running test %s", #name); \
        __block int testHarness__testFailures = 0; \
        code; \
        NSLog(@"%s Done running test %s, %d failure%s", testHarness__testFailures > 0 ? "FAILURE:" : "Success!", #name, testHarness__testFailures, testHarness__testFailures == 1 ? "" : "s"); \
        testHarness__totalFailures += testHarness__testFailures; \
    } while(0)

#define FAIL(...) testHarness__testFailures++, NSLog(@"Failed: " __VA_ARGS__)

#define ASSERT(expr) do { if(!(expr)) FAIL("assertion %s", #expr); } while(0)

static void Test(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Test();
        
        if(testHarness__totalFailures > 0) {
            NSLog(@"TESTS FAILED. %d total failed assertion%s", testHarness__totalFailures, testHarness__totalFailures == 1 ? "" : "s");
        } else {
            NSLog(@"Tests passed!");
        }
    }
    return 0;
}

static void AtomicMax(volatile int32_t *intPtr, int32_t new) {
    while(1) {
        int32_t current = *intPtr;
        if(current >= new) {
            return;
        }
        
        BOOL success = OSAtomicCompareAndSwap32(current, new, intPtr);
        if(success) {
            return;
        }
    }
}

static void Test(void) {
    TEST(async, {
        MADispatchQueue *queue = [[MADispatchQueue alloc] initSerial: YES];
        NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition: 0];
        [queue dispatchAsync: ^{
            [lock lock];
            [lock unlockWithCondition: 1];
        }];
        BOOL success = [lock lockWhenCondition: 1 beforeDate: [NSDate dateWithTimeIntervalSinceNow: 10]];
        if (success) {
            [lock unlock];
        }
        ASSERT(success);
    });
    
    TEST(sync, {
        MADispatchQueue *queue = [[MADispatchQueue alloc] initSerial: YES];
        __block BOOL done = NO;
        [queue dispatchSync: ^{
            usleep(500000);
            done = YES;
        }];
        ASSERT(done);
    });
    
    TEST(serial, {
        MADispatchQueue *queue = [[MADispatchQueue alloc] initSerial: NO];
        [queue dispatchAsync: ^{
            usleep(500000);
        }];
        
        __block int32_t activeCount = 0;
        __block int32_t maxActiveCount = 0;
        __block int32_t totalRun = 0;
        
        for(int i = 0; i < 10000; i++) {
            [queue dispatchSync: ^{
                int32_t active = OSAtomicIncrement32(&activeCount);
                AtomicMax(&maxActiveCount, active);
                usleep(100);
                OSAtomicDecrement32(&activeCount);
                
                int32_t runSoFar = OSAtomicIncrement32(&totalRun);
                ASSERT(runSoFar == i + 1);
            }];
        }
        
        [queue dispatchSync: ^{}];
        ASSERT(maxActiveCount == 1);
        ASSERT(totalRun == 10000);
    });
    
    TEST(concurrent, {
        MADispatchQueue *queue = [[MADispatchQueue alloc] initSerial: NO];
        
        __block int32_t activeCount = 0;
        __block int32_t maxActiveCount = 0;
        __block volatile int32_t totalRun = 0;
        
        for(int i = 0; i < 10000; i++) {
            [queue dispatchAsync: ^{
                int32_t active = OSAtomicIncrement32(&activeCount);
                AtomicMax(&maxActiveCount, active);
                usleep(10000);
                OSAtomicDecrement32(&activeCount);
                
                OSAtomicIncrement32(&totalRun);
            }];
        }
        
        while(totalRun < 10000) {
            usleep(1000);
        }
        
        ASSERT(maxActiveCount > 1);
        ASSERT(totalRun == 10000);
    });
    
    TEST(global, {
        __block volatile int32_t totalRun = 0;
        
        for(int i = 0; i < 10000; i++) {
            [[MADispatchQueue globalQueue] dispatchAsync: ^{
                OSAtomicIncrement32(&totalRun);
            }];
        }
        
        while(totalRun < 10000) {
            usleep(1000);
        }
    });
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值