[并发并行]_[Object-C]_[使用NSMutableArray等非线程安全集合类的注意事项]


场景:

1. 开发Mac,iOS程序时,一般都会涉及到多线程开发, 比如工作线程在更新数据模型, 主线程根据数据模型来显示界面. 

比如最常用的NSMutableArray, NSMutableDictionary等, 这类集合在调用读写方法时并不是线程安全的,也就是说会出现数据不一致性和崩溃现象.

2. 解决办法就是使用@syncronized()关键字, 有点类似Java.


test.cpp

//
//  main.c
//  test_sync
//
//  Created by daih on 11/12/15.
//  Copyright (c) 2015 infoworld. All rights reserved.
//

#include 
#import 

#include 
#include "pthread.h"
#include 
#include 

static int THREADCOUNT = 100;


// 需要多线程测试的类,类里有集合类型属性和原始类型属性.
@interface MyDevice : NSObject
{
    NSMutableArray* usbArray; // 集合类型
    NSInteger usbCount; //原始类型
}

@property(readonly) NSMutableArray* usbArray;

// 原始类型可以设置原子访问只是保证不会读脏数据,但是不能保证算数运算的同步.
// 所以还是得加锁.
@property(readwrite,assign,atomic) NSInteger usbCount;

@end

@implementation MyDevice

@synthesize usbArray;
@synthesize usbCount;

-(id)init
{
    [super init];
    usbArray = [NSMutableArray new];
    usbCount = 0;

    return self;
}

@end

static MyDevice* gDevice = [MyDevice new];
static int gCount = 0;
void* ThreadFunc(void* data)
{
    for (int i = 0; i < 10000; ++i)
    {
        // 每次+1,注意,这里gDevice.usbCount+1并不是原子操作,所以有可能多个线程的值是一样的.
        [gDevice setUsbCount:gDevice.usbCount+1];
        // 如果是多线程访问,读写usbArray都需要加锁.
        @synchronized(gDevice.usbArray)
        {
            [gDevice.usbArray addObject:@(i)];
        }
    }
    ++gCount;
    return NULL;
}

void TestSyncVariable()
{
    for (int i = 0; i < THREADCOUNT; ++i)
    {
        pthread_t t;
        pthread_create(&t,NULL,ThreadFunc,NULL);
        pthread_detach(t);
    }
}

int main(int argc, const char * argv[])
{
    // insert code here...
    CFShow(CFSTR("Hello, World!\n"));
    TestSyncVariable();
    while (gCount != THREADCOUNT)
    {
        sleep(2);
    }
    std::cout << "[gDevice.usbArray count]: " << [gDevice.usbArray count] << std::endl;
    std::cout << "gDevice.usbCount: " << gDevice.usbCount << std::endl;
    
    assert(gDevice.usbCount <= [gDevice.usbArray count]);
    assert([gDevice.usbArray count] == THREADCOUNT*10000);
    CFShow(CFSTR("Bye, World!\n"));
    return 0;
}

输出:

Hello, World!
[gDevice.usbArray count]: 1000000
gDevice.usbCount: 999997
Bye, World!
Program ended with exit code: 0

参考:

http://refactr.com/blog/2012/10/ios-tips-synchronized/



你可能感兴趣的:(C/C++多线程并发并行)