- 浏览: 44238 次
- 性别:
- 来自: 上海
最新评论
-
chengt:
http://jareye.com/
推荐一个下载jar包的网站-----jareye.com -
chengt:
http://jareye.com/
推荐一个下载jar包的网站-----jareye.com
多线程的使用与注意事项
这一回,主要介绍一下iPhone SDK中多线程的使用方法以及注意事项。虽然现在大部分PC应用程序都支持多线程/多任务的开发方式,但是在iPhone上,Apple并不推荐使用多线程的编程方式。但是多线程编程毕竟是发展的趋势,而且据说即将推出的iPhone OS4将全面支持多线程的处理方式。所以说掌握多线程的编程方式,在某些场合一定能挖掘出iPhone的更大潜力。
从例子入手
先从一个例程入手,具体的代码参考了这里。还有例程可以下载。
多线程程序的控制模型可以参考这里,一般情况下都是使用 管理者/工人模型, 这里,我们使用iPhone SDK中的 NSThread 来实现它。
首先创建一个新的 View-based application 工程,名字为 "TutorialProject" 。界面如下图所示,使用UILabel实现两部分的Part(Thread Part和Test Part),Thread Part中包含一个UIProgressView和一个UIButton;而Test Part包含一个值和一个UISlider。
接下来,在 TutorialProjectViewController.h 文件中创建各个UI控件的 IBOutlets.
同时,也需要创建outlets变量的property.
接下来定义按钮按下时的动作函数,以及slider的变化函数。
然后在 TutorialProjectViewController.m 文件中synthesize outlets,并在文件为实现dealloc释放资源。
现在开始线程部分的代码,首先当 thread button 被按下的时候,创建新的线程.
该按钮被按下后,隐藏按钮以禁止多次创建线程。然后初始化显示值和进度条,最后创建新的线程,线程的函数为 startTheBackgroundJob.
具体的 startTheBackgroundJob 函数定义如下.
在第1行,创建了一个 NSAutoreleasePool 对象,用来管理线程中自动释放的对象资源。这里 NSAutoreleasePool 在线程退出的时候释放。这符合 Cocoa GUI 应用程序的一般规则。
最后一行,阻塞调用(waitUntilDone状态是ON)函数 makeMyProgressBarMoving。
这里计算用于显示的进度条的值,利用 NSTimer ,每0.5秒自增0.01,当值等于1的时候,进度条为100%,退出函数并显示刚才被隐藏的按钮。
最后,添加 UISlider 的实现函数,用来更改主线程中 Test Part 中的 label 值
编译执行,按下线程开始按钮,你将看到进度条的计算是在后台运行。
使用线程的注意事项
线程的堆栈大小iPhone设备上的应用程序开发也是属于嵌入式设备的开发,同样需要注意嵌入式设备开发时的几点问题,比如资源上限,处理器速度等。
iPhone 中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB。并且该值不能通过编译器开关或线程API函数来更改。
你可以用下面的例子测试你的设备,这里使用POSIX Thread(pthread),设备环境是 iPhone 3GS(16GB)、SDK是3.1.3。
结果如下:
模拟器
Main thread: base:0xc0000000 / size:524288
rlimit-> soft:8388608 / hard:67104768
Thread: base:0xb014b000 / size:524288
设备
Main thread: base:0x30000000 / size:524288
rlimit-> soft:1044480 / hard:1044480
Thread: base:0xf1000 / size:524288
由此可见,当你测试多线程的程序时,模拟器和实际设备的堆栈大小是不一样的。如果有大量递归函数调用可要注意了。
Autorelease
如果你什么都不考虑,在线程函数内调用 autorelease 、那么会出现下面的错误:
一般,在线程中使用内存的模式是,线程最初
而在线程结束的时候 [pool drain] 或 [pool release]。<sup><a class="footref" name="fnr.1" href="#fn.1">1.</a></sup>
子线程中描画窗口
多线程编程中普遍遵循一个原则,就是一切与UI相关的操作都有主线程做,子线程只负责事务,数据方面的处理。那么如果想在子线程中更新UI时怎么做呢?如果是在windows下,你会 PostMessage 一个描画更新的消息,在iPhone中,需要使用performSelectorOnMainThread 委托主线程处理。
比如,如果在子线程中想让 UIImageView 的 image 更新,如果直接在线程中
这么做,什么也不会出现的。需要将该处理委托给主线程来做,像下面:
就OK了
<a class="footnum" name="fn.1" href="#fnr.1">1.</a> drain 与 release 的区别前提是你的系统中是否有GC,如果有,-drain 需要送一个消息给GC (objc_collect_if_needed),而如果没有GC,drain = release
这一回,主要介绍一下iPhone SDK中多线程的使用方法以及注意事项。虽然现在大部分PC应用程序都支持多线程/多任务的开发方式,但是在iPhone上,Apple并不推荐使用多线程的编程方式。但是多线程编程毕竟是发展的趋势,而且据说即将推出的iPhone OS4将全面支持多线程的处理方式。所以说掌握多线程的编程方式,在某些场合一定能挖掘出iPhone的更大潜力。
从例子入手
先从一个例程入手,具体的代码参考了这里。还有例程可以下载。
多线程程序的控制模型可以参考这里,一般情况下都是使用 管理者/工人模型, 这里,我们使用iPhone SDK中的 NSThread 来实现它。
首先创建一个新的 View-based application 工程,名字为 "TutorialProject" 。界面如下图所示,使用UILabel实现两部分的Part(Thread Part和Test Part),Thread Part中包含一个UIProgressView和一个UIButton;而Test Part包含一个值和一个UISlider。
接下来,在 TutorialProjectViewController.h 文件中创建各个UI控件的 IBOutlets.
@interface TutorialProjectViewController : UIViewController { // ------ Tutorial code starts here ------ // Thread part IBOutlet UILabel *threadValueLabel; IBOutlet UIProgressView *threadProgressView; IBOutlet UIButton *threadStartButton; // Test part IBOutlet UILabel *testValueLabel; // ------ Tutorial code ends here ------ }
同时,也需要创建outlets变量的property.
@property (nonatomic, retain) IBOutlet UILabel *threadValueLabel; @property (nonatomic, retain) IBOutlet UIProgressView *threadProgressView; @property (nonatomic, retain) IBOutlet UIProgressView *threadStartButton; @property (nonatomic, retain) IBOutlet UILabel *testValueLabel;
接下来定义按钮按下时的动作函数,以及slider的变化函数。
- (IBAction) startThreadButtonPressed:(UIButton *)sender; - (IBAction) testValueSliderChanged:(UISlider *)sender;
然后在 TutorialProjectViewController.m 文件中synthesize outlets,并在文件为实现dealloc释放资源。
@synthesize threadValueLabel, threadProgressView, testValueLabel, threadStartButton; ... - (void)dealloc { // ------ Tutorial code starts here ------ [threadValueLabel release]; [threadProgressView release]; [threadStartButton release]; [testValueLabel release]; // ------ Tutorial code ends here ------ [super dealloc]; }
现在开始线程部分的代码,首先当 thread button 被按下的时候,创建新的线程.
- (IBAction) startThreadButtonPressed:(UIButton *)sender { threadStartButton.hidden = YES; threadValueLabel.text = @"0"; threadProgressView.progress = 0.0; [NSThread detachNewThreadSelector:@selector(startTheBackgroundJob) toTarget:self withObject:nil]; }
该按钮被按下后,隐藏按钮以禁止多次创建线程。然后初始化显示值和进度条,最后创建新的线程,线程的函数为 startTheBackgroundJob.
具体的 startTheBackgroundJob 函数定义如下.
- (void)startTheBackgroundJob { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 线程开始后先暂停3秒(这里只是演示暂停的方法,你不是必须这么做的) [NSThread sleepForTimeInterval:3]; [self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO]; [pool release]; }
在第1行,创建了一个 NSAutoreleasePool 对象,用来管理线程中自动释放的对象资源。这里 NSAutoreleasePool 在线程退出的时候释放。这符合 Cocoa GUI 应用程序的一般规则。
最后一行,阻塞调用(waitUntilDone状态是ON)函数 makeMyProgressBarMoving。
- (void)makeMyProgressBarMoving { float actual = [threadProgressView progress]; threadValueLabel.text = [NSString stringWithFormat:@"%.2f", actual]; if (actual < 1) { threadProgressView.progress = actual + 0.01; [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeMyProgressBarMoving) userInfo:nil repeats:NO]; } else threadStartButton.hidden = NO; }
这里计算用于显示的进度条的值,利用 NSTimer ,每0.5秒自增0.01,当值等于1的时候,进度条为100%,退出函数并显示刚才被隐藏的按钮。
最后,添加 UISlider 的实现函数,用来更改主线程中 Test Part 中的 label 值
- (IBAction) testValueSliderChanged:(UISlider *)sender { testValueLabel.text = [NSString stringWithFormat:@"%.2f", sender.value]; }
编译执行,按下线程开始按钮,你将看到进度条的计算是在后台运行。
使用线程的注意事项
线程的堆栈大小iPhone设备上的应用程序开发也是属于嵌入式设备的开发,同样需要注意嵌入式设备开发时的几点问题,比如资源上限,处理器速度等。
iPhone 中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB。并且该值不能通过编译器开关或线程API函数来更改。
你可以用下面的例子测试你的设备,这里使用POSIX Thread(pthread),设备环境是 iPhone 3GS(16GB)、SDK是3.1.3。
#include "pthread.h" void *threadFunc(void *arg) { void* stack_base = pthread_get_stackaddr_np(pthread_self()); size_t stack_size = pthread_get_stacksize_np(pthread_self()); NSLog(@"Thread: base:%p / size:%u", stack_base, stack_size); return NULL; } - (void)applicationDidFinishLaunching:(UIApplication *)application { void* stack_base = pthread_get_stackaddr_np(pthread_self()); size_t stack_size = pthread_get_stacksize_np(pthread_self()); struct rlimit limit; getrlimit(RLIMIT_STACK, &limit); NSLog(@"Main thread: base:%p / size:%u", stack_base, stack_size); NSLog(@" rlimit-> soft:%llu / hard:%llu", limit.rlim_cur, limit.rlim_max); pthread_t thread; pthread_create(&thread, NULL, threadFunc, NULL); // Override point for customization after app launch [window addSubview:viewController.view]; [window makeKeyAndVisible]; }
结果如下:
模拟器
Main thread: base:0xc0000000 / size:524288
rlimit-> soft:8388608 / hard:67104768
Thread: base:0xb014b000 / size:524288
设备
Main thread: base:0x30000000 / size:524288
rlimit-> soft:1044480 / hard:1044480
Thread: base:0xf1000 / size:524288
由此可见,当你测试多线程的程序时,模拟器和实际设备的堆栈大小是不一样的。如果有大量递归函数调用可要注意了。
Autorelease
如果你什么都不考虑,在线程函数内调用 autorelease 、那么会出现下面的错误:
NSAutoReleaseNoPool(): Object 0x********* of class NSConreteData autoreleased with no pool in place ….
一般,在线程中使用内存的模式是,线程最初
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
而在线程结束的时候 [pool drain] 或 [pool release]。<sup><a class="footref" name="fnr.1" href="#fn.1">1.</a></sup>
子线程中描画窗口
多线程编程中普遍遵循一个原则,就是一切与UI相关的操作都有主线程做,子线程只负责事务,数据方面的处理。那么如果想在子线程中更新UI时怎么做呢?如果是在windows下,你会 PostMessage 一个描画更新的消息,在iPhone中,需要使用performSelectorOnMainThread 委托主线程处理。
比如,如果在子线程中想让 UIImageView 的 image 更新,如果直接在线程中
imageView.image = [UIImage imageNamed:@"Hoge.png"];
这么做,什么也不会出现的。需要将该处理委托给主线程来做,像下面:
[delegate performSelectorOnMainThread:@selector(theProcess:) withObject:nil waitUntilDone:YES];
就OK了
<a class="footnum" name="fn.1" href="#fnr.1">1.</a> drain 与 release 的区别前提是你的系统中是否有GC,如果有,-drain 需要送一个消息给GC (objc_collect_if_needed),而如果没有GC,drain = release
发表评论
-
iOS开发中如何解决TableView中图片延时加载
2012-06-01 13:44 1631IOS开发中如何解决TableView中图片延时加载是本文要介 ... -
让模拟器也支持GPS定位(模拟实现)
2012-06-01 13:36 2134iOS上的GPS定位一般需要真机才能看到效果,但在开发的过程中 ... -
判断UITextField的输入只为数字的方法
2012-06-01 13:35 1131实现下面的委托 #define NUMBERS @" ... -
反向地理编码用法
2012-06-01 13:33 1135与地图打交道时,有时需要查找经纬度获取地理信息,MapKit提 ... -
关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案
2012-06-01 13:31 659随着用xcode开发的深入,相信很多同学都对出现SIGBAT或 ... -
iOS 应用的 UI 开发资源
2012-05-28 23:27 944中文 http://blog.csdn.net/column ... -
汉字转拼音
2012-05-20 19:47 988// // ChineseToPinyin.h // ... -
修改图标上的提示符(badge)
2012-05-20 19:35 957程序推送,或者AppStore软件有更新都会有提示,那代码怎么 ... -
Info.plist中常用的key简介
2012-05-20 19:10 917UIRequiresPersistentWiFi 在程序中弹出 ... -
返回 父级 的父级 view
2012-05-09 14:48 889[color=blue]有3个view A,B,C A是第一级 ... -
如何获取view的controller
2012-05-09 14:45 1487[b]如何获取view的controller[/b] ... -
xcode4 svn+ssh
2012-05-04 22:18 11211. Clear the contents of your ~ ... -
在程序中使用GPS定位
2012-03-17 10:28 854这一回简单地介绍一下G ... -
开源ZXing在XCode上如何使用
2012-03-17 10:18 9701.在 zxing/iphone/ZXingWidget/里的 ... -
iphone 二维码 使用说明
2012-03-17 10:16 1103转自:http://blog.csdn.net/linkai5 ... -
iphone开发随笔,有用的
2012-03-14 20:52 7421.将view设置成圆角 首先导入QuartzCore.fra ... -
iphone开发中发送短信
2012-03-14 20:46 1321iOS4.0新加入了MFMessageComposeViewC ... -
iphone中设置控件语言
2012-03-14 20:40 876最近项目遇到这样一个问题: 发送短信时,发现控件显示的是英 ... -
How to use ZXing(decode qr code) .
2012-03-14 20:26 1269ZXing for iOS is a sub-project ... -
SVN+SSH
2012-03-10 20:00 1111Setup SSH access Go to the cPan ...
相关推荐
总结C++中多线程要注意的事项,不能跨线程调用MFC对象等等
MFC多线程编程注意事项,很不错的资料。
多线程调用DBUS服务注意事项 多线程调用DBUS服务是一个复杂的任务,需要遵循一些重要的注意事项,以确保正确地调用DBUS服务。下面是多线程调用DBUS服务的四个重要注意事项: 1. 多线程初始化 在多线程环境中调用...
JAVA多线程的使用场景与注意事项总结 Java多线程是Java语言中的一种重要机制,允许程序同时执行多个任务,以提高程序的执行效率和响应速度。在Java中,多线程可以通过继承Thread类、实现Runnable接口或使用线程池来...
在iOS开发中,多线程的使用是提升应用程序性能和用户体验的重要手段。本文将详细介绍如何在iPhone SDK中使用多线程以及需要注意的关键点。 多线程允许程序在执行过程中同时进行多个任务,使得用户界面(UI)保持...
批量爬虫下载时,单线程下载文件有时慢有时快。...同时附上单线程下载(带进度条显示功能)代码,单线程下载(带进度条显示)和多线程代码的时间比较,实测多线程能有效提升下载效率,效果还是比较不错的。
多线程使用时的注意事项: - **线程安全**:无论是哪种Timer,当在回调或事件处理程序中访问共享数据或UI控件时,都需要确保线程安全。使用`lock`关键字、`Monitor`类或.NET的线程同步机制(如`Interlocked`)来防止...
6. 多线程的挑战与注意事项:虽然多线程带来了性能提升,但同时也引入了复杂性,比如数据一致性问题、竞态条件、死锁等。开发者在使用多线程时需要注意避免这些问题,合理规划线程的生命周期,以及合理使用同步机制...
通过阅读源码,我们可以学习到具体的操作步骤和注意事项,例如线程同步、异常处理等。 总之,易语言多线程传递多参数是一项关键的编程技能,它涉及到线程的创建、管理和参数传递。理解并掌握这些知识,能够帮助...
描述了c++的多线程的注意事项。包括不能跨线程访问MFC对象等
4. **优化与注意事项**: - **线程池大小设置**:应根据系统资源和任务特性合理设置,过大可能导致资源浪费,过小可能造成阻塞。 - **拒绝策略选择**:根据业务需求选择合适的策略,防止系统崩溃或丢失数据。 - *...
在Spring Boot中,多线程开发是提升应用性能和并发能力的重要手段。Spring Boot通过`TaskExecutor`接口提供了一种方便的方式来实现多线程和...理解并遵循这些注意事项将有助于构建健壮、高效的多线程Spring Boot应用。
多线程编程的注意事项: * 需要同步线程的执行,以避免数据的不一致 * 需要正确地处理线程的生命周期 * 需要注意线程的优先级和调度 在 VS2013 平台中,创建多线程可以使用 CreateThread 函数或 AfxBeginThread ...
书中以muduo网络库为例,讲解这种编程模型的使用方法及注意事项。 《Linux多线程服务端编程:使用muduo C++网络库》的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更...
本书以muduo 网络库为例,讲解这种编程模型的使用方法及注意事项。 本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种...
这些API的使用方法和注意事项是多线程编程实践中的重要知识,书中会有具体的代码示例帮助理解。 在多线程编程中,线程同步是避免数据竞争和死锁的关键。本书深入浅出地介绍了各种同步机制,如临界区(Critical ...
Delphi2010多线程编程教程旨在帮助开发者快速掌握多线程编程的要领,包括基础知识、使用TThread类和CreateThread函数实现多线程、注意事项和实例代码分析等内容。本教程适合初学者和有经验的开发者,旨在帮助他们...
注意事项** - GUI操作应始终在主线程中进行,因为Qt的GUI组件不是线程安全的。 - 使用`QThread::quit()`或`QThread::wait()`来优雅地终止线程,避免资源泄漏。 - 避免在线程之间共享复杂的Qt对象,除非使用`QThread...
4. **注意事项**: 每个浏览器实例需要独立的Chromedriver,并且在多线程环境下,要注意同步问题,防止不同线程间的操作相互干扰。 总结起来,"python selenium chrome 多开 多线程"这个主题涉及到使用Python的...