任何语言都不能避而不谈线程这个东东,虽然他是和平台相关的鸟,虽说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)[线程和操作队列]的更多相关文章

  1. obj-c编程10:Foundation库中类的使用(2)[字符串,数组]

    Foundation库的内容不可谓不多,就算很精简的说篇幅也受不了啊!笨猫一向反对博客文章一下子拖拖拉拉写一大坨!KISS哦!so将上一篇文章再分一篇来说,于是有了这篇,可能还会有(3)哦... 我发 ...

  2. obj-c编程10:Foundation库中类的使用(5)[时间对象]

    隔了好久才有了这新的一篇,还是无奈的时间啊!so这次我们就着重谈谈它喽. F库中有很多时间相关的类,比如NSDate,NSTimeInterval,NSTimeZone,NSDateComponent ...

  3. obj-c编程10:Foundation库中类的使用(4)[文件管理,查询当前进程信息]

    接上一篇文件管理博文.我们可以用NSPathUtilities.h中包含的NSString函数和分类扩展来以兼容的方式处理路径.下面凡是有系统编程经验的童鞋都知道是啥意思了: #import < ...

  4. obj-c编程10:Foundation库中类的使用(3)[文件管理]

    好吧,不管神马系统都无可避免的要说到文件,目录,路径(PATH)管理的内容,下面我们来看看在F库中对他们的支持.我简单看了下,不谈其他光从方法命名来说就多少显得有点复杂,如果和ruby相比就呵呵了. ...

  5. obj-c编程10:Foundation库中类的使用(1)[数字,字符串]

    我们知道在mac或iphone上编程最终逃不开os x平台,你无法在windows或linux上开发纯正的apple程序.(so不要舍不得银子买mac啦)虽说linux和windows上有移植的obj ...

  6. C++的XML编程经验――LIBXML2库使用指南[转]

    C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...

  7. Java 库:为 Java 程序员而生的 10 + 最佳库

    众所周知,Java 的生态环境相当庞大,包含了数量相当可观的官方及第三方库.利用这些库,可以解决在用 Java 开发时遇到的各类问题,让开发效率得到显著提升. 举些例子,最常用的官方库有 java.l ...

  8. C++的XML编程经验――LIBXML2库使用指南

    C++的XML编程经验――LIBXML2库使用指南 写这篇文章的原因有如下几点:1)C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,LIBXML2是其中一种很优秀的XML ...

  9. 并发编程 10—— 任务取消 之 关闭 ExecutorService

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

随机推荐

  1. 百度地图SDK3.4的使用

    使用过百度地图的开发者应该都知道原始百度地图的开发的基本流程,但是随着百度地图的更新,百度地图的api有了翻天覆地的变化,最新版本的sdk为v3.4 2015年4月14日上线,优化了许多接口的设计,简 ...

  2. Android 系统当中各种尺寸单位的定义及使用

    一,Android 各种标尺单位的含义: px:表示屏幕实际的象素.例如,320*480的屏幕在横向有320个象素,在纵向有480个象素.pt:表示一个点,是屏幕的物理尺寸.大小为1英寸的1/72.i ...

  3. ROS_Kinetic_24 使用catkin_create_qt_pkg快速创建qt-ros功能包

    使用catkin_create_qt_pkg快速创建qt-ros功能包 参考网址: qt_create:http://wiki.ros.org/qt_create qt_ros:https://git ...

  4. Linux上程序调试的基石(2)--GDB

    3. GDB的实现 GDB是GNU发布的一个强大的程序调试工具,用以调试C/C++程序.可以使程序员在程序运行的时候观察程序在内存/寄存器中的使用情况.它的实现也是基于ptrace系统调用来完成的.  ...

  5. 还在繁琐的敲MVP接口和实现类吗,教你一秒搞定。

    只有程序员懒起来,才能提高开发效率 233333 在MVP的使用过程中,我们需要反复的去写各种MVP的接口和实现类, 实在是 太麻烦了!!所以抽时间撸了一款插件(只可用于Intellj IDEA 和 ...

  6. 用SpriteBuilder简化"耕牛遍地走"的动画效果(四)

    写到这突然有童鞋质疑,你这哪里是牛,分明是熊嘛! 仔细看了下,还真像牛.反正是这个意思.怪本猫猪牛熊不分,好在道理是一样的. 下面继续,言归正传. 添加一个空白的touchBegan方法,如果没有这个 ...

  7. HBase作为存储方案

    HBase存储特点 * Client 1. 包含访问HBase的接口,并维护cache来加快对HBase的访问,比如region的位置信息. * Zookeeper: 1. 选举集群中的Master, ...

  8. Spark1.4从HDFS读取文件运行Java语言WordCounts

    Hadoop:2.4.0 Spark:1.4.0 Ubuntu 14.0 1.首先启动Hadoop的HDFS系统.     HADOOP_HOME/sbin/start-dfs.sh 2.在Linux ...

  9. JAVA之旅(二十一)——泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符

    JAVA之旅(二十一)--泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符 不知不觉JAVA之旅已经写到21篇了,不得不感叹当初自己坚持要重学一遍JAVA的信念,中途也算 ...

  10. 《重构》中Tips总结

    1         如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达到目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性. 2         重构之前,首先检查自己 ...