obj-c编程10:Foundation库中类的使用(6)[线程和操作队列]
任何语言都不能避而不谈线程这个东东,虽然他是和平台相关的鸟,虽说unix哲学比较讨厌线程的说...线程不是万能灵药,但有些场合还是需要的.谈到线程就不得不考虑同步和死锁问题,见如下代码:
#import <Foundation/Foundation.h>
#define msg(...) NSLog(__VA_ARGS__)
@interface Foo:NSObject{
int i;
//NSLock *lock;
NSRecursiveLock *lock;
}
@property(atomic) int i;
@end
@implementation Foo
@synthesize i;
-(id)init{
self = [super init];
if(self){
i = 0;
//lock = [[NSLock alloc] init];
lock = [[NSRecursiveLock alloc] init];
}
return self;
}
-(void)loop{
int org_i = 0;
for(int x = 0;x < 5000;++x){
org_i = i;
[self inc];
//self.i++;
msg(@"%@:i has %d to %d",[[NSThread currentThread] name],\
org_i,i);
}
}
-(void)inc{
//@synchronized(self){
[lock lock];
i++;
[lock unlock];
//}
}
-(int)val{
return i;
}
@end
#define msg(...) NSLog(__VA_ARGS__)
int main(int argc,char *argv[])
{
@autoreleasepool{
id t = nil;
Foo *foo = [[Foo alloc] init];
NSMutableArray *ary = [[NSMutableArray alloc]init];
for(int i = 0;i<10;++i){
t = [[NSThread alloc] initWithTarget:foo selector:@selector(loop) \
object:nil];
[t setName:[NSString stringWithFormat:@"thread_%d",i]];
[ary addObject:t];
}
for(NSThread *t in ary){
[t start];
}
BOOL quit = NO;
while(true){
for(NSThread *t in ary){
quit = [t isFinished];
if(!quit) break;
}
if(quit) break;
[NSThread sleepForTimeInterval:1.0];
}
msg(@"at last val is %d",[foo val]);
}
return 0;
}
以上代码涉及到线程的创建和同步代码.除了通过线程实例方法initWithTarget:...方法创建以外还可以通过线程类方法+detachNewThreadSelector:...来创建,后一种方法创建后线程立即执行,而前一种方法需要使用-start方法启动线程.线程的同步可以通过NSLock类的lock和unlock方法,或者可以使用obj-c的关键字:@synchronize来实现快速快速同步语义.对于类属性来说,可以通过关键字atomic来声明该属性的原子性,不过实际执行好像不能确保同步,本猫哪里没考虑到呢?
我在使用NSURLConnection类获取网络数据的时候发现协议回调方法无法被回调,开始我以为可能回调需要时间执行,所以我在主线程中使用了循环+sleep函数等待其isFinished回调的完成.但是这个循环永远也不会结束.后来发现NSURLConnection类的工作需要在主线程的"剩余时间片"中完成,所以你sleep还是不行,等于主线程直接睡眠了不会分到时间片啊.这时你可以使用F库中提供的NSRunLoop类的功能来完成:
[[NSRunLoop currentRunLoop] runUntilDate ...]
Cocoa GUI框架不是线程安全的,这意味着其他线程如果需要更新GUI组件必须通过主线程来实现,这可以通过NSObject实例方法-performSelectorOnMainThread:withObject:waitUntilDone:来实现;同样的除了指定让主线程做事之外,还可以指定让其他后台线程上执行选择器:-performSelector:onThread:waitIntilDone: .
线程是一种比较底层的OS提供的接口,obj-c提供了包装线程的更高级的逻辑接口,这就是NSOperation和NSOperationQueue类,这种新型线程模型核心称为GCD.你只需把需要完成的任务放入NSOperationQueue队列中,该队列会根据系统cpu情况自动生成和销毁一定数目的线程来完成工作,你就不用操心啦.你可以派生NSOperation类并覆写其main方法来添加任务单元;你也可以使用F库自带的更方便的更专注于任务的NSInvocationOperation和NSBlockOperation类来描述任务单元.最后你可以使用-waitUntilAllOperationsAreFinished方法等待队列中所有任务都完成.下面我写了一个简单的利用队列多线程完成任务的代码,每一项任务单元就是给文件改名(但不改文件夹的名字),所有都在代码里喽:
#import <Foundation/Foundation.h>
#define msg(...) printf("[%d]\n",__LINE__);NSLog(__VA_ARGS__)
@interface RenameConcur:NSObject{
NSString *path;
NSString *prefix;
}
@property NSString *path;
@property NSString *prefix;
-(id)initWithPath:(NSString*)path andPrefix:(NSString*)prefix;
-(void)renameWithPrefix;
@end
@implementation RenameConcur
@synthesize path,prefix;
-(id)initWithPath:(NSString*)path_v andPrefix:(NSString*)prefix_v{
self = [super init];
if(self){
path = [path_v stringByExpandingTildeInPath];
prefix = prefix_v;
}
return self;
}
-(id)init{
return [self initWithPath:nil andPrefix:nil];
}
-(void)renameWithPrefix{
if(!prefix || !path){
msg(@"obj's prefix or path is nil!");
}
else{
NSFileManager *fm = [NSFileManager defaultManager];
BOOL is_dir = NO;
if([fm fileExistsAtPath:path isDirectory:&is_dir] == NO){
msg(@"file %@ is not exist!",path);
return;
}else if(is_dir){
msg(@"path %@ is directory,do nothing!",path);
return;
}
NSString *just_name = [path lastPathComponent];
NSString *just_path = [path stringByDeletingLastPathComponent];
NSString *new_path = [NSString stringWithFormat:@"%@/%@%@",just_path,prefix,just_name];
if([fm moveItemAtPath:path toPath:new_path error:NULL] == NO){
msg(@"rename %@ to %@ failed!",path,new_path);
return;
}
}
}
@end
int main(int argc,char *argv[])
{
@autoreleasepool{
/*
NSString *path = @"~/src/objc_src/ddd.m";
NSString *prefix = @"love_";
RenameConcur *rnc = [[RenameConcur alloc] initWithPath:path andPrefix:prefix];
[rnc renameWithPrefix];
NSString *dir_path = [@"~/src/dir_love" stringByExpandingTildeInPath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:dir_path error:NULL];
msg(@"files : %@",files);
for(NSString *file in files){
[rnc setPath:[NSString stringWithFormat:@"%@/%@",dir_path,file]];
[rnc renameWithPrefix];
}
*/
NSProcessInfo *process = [NSProcessInfo processInfo];
NSArray *args = [process arguments];
if([args count] != 3){
printf("usage : %s path prefix (notice : path's end don't with /)\n",\
[[[args objectAtIndex:0] lastPathComponent] \
cStringUsingEncoding:NSASCIIStringEncoding]);
return 1;
}
NSString *dir_path = [[args objectAtIndex:1] stringByExpandingTildeInPath];
NSString *prefix = [args objectAtIndex:2];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:dir_path error:NULL];
if(!files){
msg(@"get dir [%@] files's name failed!",dir_path);
return 2;
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for(NSString *file in files){
RenameConcur *rnc_n = [[RenameConcur alloc] initWithPath:\
[NSString stringWithFormat:@"%@/%@",dir_path,file] andPrefix:prefix];
NSOperation *op = [[NSInvocationOperation alloc] initWithTarget:rnc_n \
selector:@selector(renameWithPrefix) object:nil];
[queue addOperation:op];
}
[queue waitUntilAllOperationsAreFinished];
}
return 0;
}
obj-c编程10:Foundation库中类的使用(6)[线程和操作队列]的更多相关文章
- obj-c编程10:Foundation库中类的使用(2)[字符串,数组]
Foundation库的内容不可谓不多,就算很精简的说篇幅也受不了啊!笨猫一向反对博客文章一下子拖拖拉拉写一大坨!KISS哦!so将上一篇文章再分一篇来说,于是有了这篇,可能还会有(3)哦... 我发 ...
- obj-c编程10:Foundation库中类的使用(5)[时间对象]
隔了好久才有了这新的一篇,还是无奈的时间啊!so这次我们就着重谈谈它喽. F库中有很多时间相关的类,比如NSDate,NSTimeInterval,NSTimeZone,NSDateComponent ...
- obj-c编程10:Foundation库中类的使用(4)[文件管理,查询当前进程信息]
接上一篇文件管理博文.我们可以用NSPathUtilities.h中包含的NSString函数和分类扩展来以兼容的方式处理路径.下面凡是有系统编程经验的童鞋都知道是啥意思了: #import < ...
- obj-c编程10:Foundation库中类的使用(3)[文件管理]
好吧,不管神马系统都无可避免的要说到文件,目录,路径(PATH)管理的内容,下面我们来看看在F库中对他们的支持.我简单看了下,不谈其他光从方法命名来说就多少显得有点复杂,如果和ruby相比就呵呵了. ...
- obj-c编程10:Foundation库中类的使用(1)[数字,字符串]
我们知道在mac或iphone上编程最终逃不开os x平台,你无法在windows或linux上开发纯正的apple程序.(so不要舍不得银子买mac啦)虽说linux和windows上有移植的obj ...
- C++的XML编程经验――LIBXML2库使用指南[转]
C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...
- Java 库:为 Java 程序员而生的 10 + 最佳库
众所周知,Java 的生态环境相当庞大,包含了数量相当可观的官方及第三方库.利用这些库,可以解决在用 Java 开发时遇到的各类问题,让开发效率得到显著提升. 举些例子,最常用的官方库有 java.l ...
- C++的XML编程经验――LIBXML2库使用指南
C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...
- 并发编程 10—— 任务取消 之 关闭 ExecutorService
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
随机推荐
- socket系列之服务器端socket——ServerSocket类
一般地,Socket可分为TCP套接字和UDP套接字,再进一步,还可以被分为服务器端套接字跟客户端套接字.这节我们先关注TCP套接字的服务器端socket,Java中ServerSocket类与之相对 ...
- Android之EditText imeOptions属性解析
在我们的手机中,虽然通常输入法软键盘右下角会是回车按键,但我们经常会看到点击不同的编辑框,输入法软键盘右下角会有不同的图标.例如: 点击浏览器网址栏的时候,输入法软键盘右下角会变成"GO& ...
- Android的四个基本概念(线程通信和GLSurfaceView)
GLSurfaceView提供了下列特性: 1> 管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上. 2> 管理一个EGL disp ...
- 如何正确的理解和解决 ORA-01843:not a valid month
今天码代码的时候遇到了这个问题,因为oracle用的比较少,所在查询了一下. 顿时傻眼,有很多的贴子说是因为nls_date_language的问题,还要改会话级的NLS_DATE_LANGUAGE设 ...
- 后端分布式系列:分布式存储-HDFS 与 GFS 的设计差异
「后端分布式系列」前面关于 HDFS 的一些文章介绍了它的整体架构和一些关键部件的设计实现要点. 我们知道 HDFS 最早是根据 GFS(Google File System)的论文概念模型来设计实现 ...
- Android的搜索框SearchView的用法-android学习之旅(三十九)
SearchView简介 SearchView是搜索框组件,他可以让用户搜索文字,然后显示.' 代码示例 这个示例加了衣蛾ListView用于为SearchView增加自动补全的功能. package ...
- UNIX网络编程——shutdown 与 close 函数 的区别
假设server和client 已经建立了连接,server调用了close, 发送FIN 段给client(其实不一定会发送FIN段,后面再说),此时server不能再通过socket发送和接收数据 ...
- hive的数据导入与数据导出:(本地,云hdfs,hbase),列分隔符的设置,以及hdfs上传给pig如何处理
hive表的数据源有四种: hbase hdfs 本地 其他hive表 而hive表本身有两种: 内部表和外部表. 而hbase的数据在hive中,可以建立对应的外部表(参看hive和hbase整合) ...
- LOV里的值直接引用系统里定义的值集的值,且具有值集的安全性控制
fnd_flex_server.check_value_security(p_security_check_mode => 'YH', p_flex_value_set_id => p_f ...
- JDK6和JDK7中String的substring()方法及其差异
翻译人员: 铁锚 翻译日期: 2013年11月2日 原文链接: The substring() Method in JDK 6 and JDK 7 在JDK6与JDK7这两个版本中,substri ...