[并发并行]_[Object-C]_[使用NSMutableArray等非线程安全集合类的注意事项]
2015-11-12 15:40
447 查看
场景:
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 <CoreFoundation/CoreFoundation.h>
#import <Cocoa/Cocoa.h>
#include <iostream>
#include "pthread.h"
#include <stdio.h>
#include <assert.h>
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/
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 <CoreFoundation/CoreFoundation.h>
#import <Cocoa/Cocoa.h>
#include <iostream>
#include "pthread.h"
#include <stdio.h>
#include <assert.h>
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/
相关文章推荐
- [并发并行]_[Object-C]_[使用NSMutableArray等非线程安全集合类的注意事项]
- fastjson包JSONObject.toJSON导致DTO部分属性丢失问题
- swfobject.js的简单配置
- VC++ error C2248: “CObject::CObject”: 无法访问 private 成员(在“CObject”类中声明)
- From C++ to Objective-C
- iOS 程序报错:reason: [NSArrayI addObject:]: unrecognized selector sent to instance
- Objective C运行时(runtime)技术的几个要点总结
- object-c:委托(delegate)
- Objective-C的Runtime
- 使用Xcode HeaderDoc和Doxygen文档化你的Objective-C和Swift代码
- checkBox1_CheckedChanged(object sender, EventArgs e)和checkBox1_CheckStateChanged(object sender, EventArgs e)不同
- C# waitformultipleobjects()
- objective-c 学习第一节 HelloWorld
- [Javascript] Object.assign()
- django object is not JSON serializable error问题解决
- OpenGL ES 3.0之Fragment buffer objects(FBO)详解(二)
- Objective_C基础之NSArray整理
- Objective_C基础之NSDictionary整理
- Objective_C基础之NSString整理
- Xcode中Objective-C和C++混编的实现 (二)