iOS 线程管理的学习记录
- 本文转载至 http://www.2cto.com/kf/201312/265451.html
-
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
- (
void
)method1
{
NSLog(@%@,NSStringFromSelector(_cmd));
}
- (
void
)method2
{
NSLog(@%@,NSStringFromSelector(_cmd));
}
/*
线程1锁住之后,线程2会一直等待走到线程1将锁置为unlock后,才会执行method2方法。
NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。
*/
- (IBAction)NSLock:(id)sender {
NSLock *lock = [[NSLock alloc] init];
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
[lock lock];
[self method1];
sleep(
10
);
[lock unlock];
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
sleep(
1
);
//以保证让线程2的代码后执行
[lock lock];
[self method2];
[lock unlock];
});
}
/*
@synchronized指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj)改为@synchronized(other),刚线程2就不会被阻塞,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
*/
- (IBAction)
synchronized
:(id)sender {
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
@synchronized
(self){
[self method1];
sleep(
5
);
}
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
sleep(
1
);
@synchronized
(self){
[self method2];
}
});
}
- (IBAction)pthread_mutex_t:(id)sender {
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
pthread_mutex_lock(&mutex);
[self method1];
sleep(
5
);
pthread_mutex_unlock(&mutex);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
sleep(
1
);
pthread_mutex_lock(&mutex);
[self method2];
pthread_mutex_unlock(&mutex);
});
}
- (IBAction)GCD:(id)sender {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(
1
);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self method1];
sleep(
10
);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
sleep(
1
);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self method2];
dispatch_semaphore_signal(semaphore);
});
}
/* NSRecursiveLock递归锁
在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了,由于以上的代码非常的简短,所以很容易能识别死锁,但在较为复杂的代码中,就不那么容易发现了,那么如何在递归或循环中正确的使用锁呢?此处的theLock如果换用NSRecursiveLock对象,问题便得到解决了,NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。
*/
- (IBAction)NSRecursiveLock:(id)sender {
NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
// TestObj *obj = [[TestObj alloc] init];
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
static
void
(^TestMethod)(
int
);
TestMethod = ^(
int
value)
{
[theLock lock];
if
(value >
0
)
{
[self method1];
sleep(
5
);
TestMethod(value-
1
);
}
[theLock unlock];
};
TestMethod(
5
);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
sleep(
1
);
[theLock lock];
[self method2];
[theLock unlock];
});
}
/* NSConditionLock条件锁
在线程1中的加锁使用了lock,所以是不需要条件的,所以顺利的就锁住了,但在unlock的使用了一个整型的条件,它可以开启其它线程中正在等待这把钥匙的临界地,而线程2则需要一把被标识为2的钥匙,所以当线程1循环到最后一次的时候,才最终打开了线程2中的阻塞。但即便如此,NSConditionLock也跟其它的锁一样,是需要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是可以随意组合的,当然这是与你的需求相关的。
*/
- (IBAction)NSConditionLock:(id)sender {
//主线程中
NSConditionLock *theLock = [[NSConditionLock alloc] init];
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
for
(
int
i=
0
;i<=
2
;i++)
{
[theLock lock];
NSLog(
@thread1
:%d,i);
sleep(
2
);
[theLock unlockWithCondition:i];
}
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
[theLock lockWhenCondition:
2
];
NSLog(
@thread2
);
[theLock unlock];
});
}
今天发现了非常好的线程管理的文章,特此贴出来学习一下,最后还有一块并没有试验,再次也贴出来,大家可以参考一下
NSDistributedLock分布式锁
以上所有的锁都是在解决多线程之间的冲突,但如果遇上多个进程或多个程序之间需要构建互斥的情景该怎么办呢?这个时候我们就需要使用到NSDistributedLock了,从它的类名就知道这是一个分布式的Lock,NSDistributedLock的实现是通过文件系统的,所以使用它才可以有效的实现不同进程之间的互斥,但NSDistributedLock并非继承于NSLock,它没有lock方法,它只实现了tryLock,unlock,breakLock,所以如果需要lock的话,你就必须自己实现一个tryLock的轮询,下面通过代码简单的演示一下吧
12345678dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
lock = [[NSDistributedLock alloc] initWithPath:@/Users/mac/Desktop/earning__];
[lock breakLock];
[lock tryLock];
sleep(
10
);
[lock unlock];
NSLog(
@appA
: OK);
});
12345678910dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0
), ^{
lock = [[NSDistributedLock alloc] initWithPath:@/Users/mac/Desktop/earning__];
while
(![lock tryLock]) {
NSLog(
@appB
: waiting);
sleep(
1
);
}
[lock unlock];
NSLog(
@appB
: OK);
});
先运行程序A,然后立即运行程序B,根据打印你可以清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒过后,程序B便打印出了appB:OK的输出,以上便实现了两上不同程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在tryLock返回YES时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。
个人觉得除了这些以外,之前还在工作当中用到过一个关于NSTimer的线程管理,那就是timer的暂停和继续,在此也贴出代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051//为NSTimer添加一个分类
#
import
TFTimer.h
#
import
<foundation foundation.h=
""
>
@interface
NSTimer (TFAddition)
-(
void
)pauseTimer;
-(
void
)resumeTimer;
@end
#
import
TFTimer.h
@implementation
NSTimer (TFAddition)
-(
void
)pauseTimer{
if
(![self isValid]) {
return
;
}
[self setFireDate:[NSDate distantFuture]];
//如果给我一个期限,我希望是4001-01-01 00:00:00 +0000
}
-(
void
)resumeTimer{
if
(![self isValid]) {
return
;
}
//[self setFireDate:[NSDate dateWithTimeIntervalSinceNow:0]];
[self setFireDate:[NSDate date]];
}
@end
</foundation>
iOS 线程管理的学习记录的更多相关文章
- Android权限管理知识学习记录
一.Android权限背景知识 在Android 6.0之前,所申请的权限只需要在AndroidManifest.xml列举就可以了,从而容易导致一些安全隐患,因此,在Android 6.0时,Goo ...
- iOS - 线程管理
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- IOS内存管理学习笔记
内存管理作为iOS中非常重要的部分,每一个iOS开发者都应该深入了解iOS内存管理,最近在学习iOS中整理出了一些知识点,先从MRC开始说起. 1.当一个对象在创建之后它的引用计数器为1,当调用这个对 ...
- ios 多线程开发(二)线程管理
线程管理 iOS和OS X中每一个进程(或程序)由一个或多个线程组成.程序由一个运行main方法的线程开始,中间可以产生其他线程来执行一些指定的功能. 当程序产生一个新线程后,这个线程在程序进程空间内 ...
- JVM学习记录-线程安全与锁优化(二)
前言 高效并发是程序员们写代码时一直所追求的,HotSpot虚拟机开发团队也为此付出了很多努力,为了在线程之间更高效地共享数据,以及解决竞争问题,HotSpot开发团队做出了各种锁的优化技术常见的有: ...
- 【iOS开发-33】学习手动内存管理临时抛弃ARC以及retain/assign知识——iOSproject师面试必考内容
我们为什么须要内存管理?当使用内存达到40M和45M时候会发出警告,假设不处理,占用内存达到120M时直接强制关闭程序. 所以出现闪退除了是程序出现逻辑错误,还有可能是内存使用过大. (1)创建一个对 ...
- 巨蟒django之CRM5 学习记录&&课程记录&&班级管理&&私户的数量上限
1.公户变私户(事务+行级锁) 2.私户的数量上限 3.班级的管理 4.课程记录管理 5.学习记录的初始化 6.展示和编辑学习记录
- ucore操作系统学习(四) ucore lab4内核线程管理
1. ucore lab4介绍 什么是进程? 现代操作系统为了满足人们对于多道编程的需求,希望在计算机系统上能并发的同时运行多个程序,且彼此间互相不干扰.当一个程序受制于等待I/O完成等事件时,可以让 ...
- RT-Thread学习2 —— 内存管理学习记录
RT-Thread学习2 -- 内存管理学习记录1 小内存管理算法(mem.c) 1. 小内存管理法: 小内存管理算法是一个简单的内存分配算法.初始时,它是一块大的内存.当需要分配内存块时,将从这个大 ...
随机推荐
- win10 安装java
https://jingyan.baidu.com/article/fea4511a12b158f7bb9125b9.html 一 下载java SE 官网 二设置环境变量 JAVA_HOME PAT ...
- python 读取CSV文件 中文乱码
今天读取一个CSV文件,打印出来,中文显示乱码,原因是编码的缘故,CSV保存是编码格式ANSI,解决办法是以记事本方式打开CSV文件,然后另存为时编码选择UTF-8进行保存即可.
- 解决dubbo问题:forbid consumer(1)
原因: 1.dubbo服务没有起动起来 2.dubbo链接的地址出现异常 3.dubbo服务端更新了服务接口,没有发布 如果已上都没有问题,那么还有一个原因就是 “ 别人的代码有问题 阻碍了 你的程序 ...
- Node.js 文件系统流pipe到Http响应流中
// 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http"); var fs=req ...
- 【转载】WEB系统性能问题的分析定位方法
以一个典型的WEB系统来举例,性能问题一般体现在客户端请求后的响应时间上.在性能测试过程中,即压力增大到某个程度后,响应时间指标迅速增长.但如那篇文章所说,这只能叫做一个现象,测试人员需要找到问题所在 ...
- HTML 5 音频Audio
在HTML5标准网页里面,我们能够运用audio标签来完毕我们对声音的调用及播放. 下面是最常常见到的运用HTML5三种基本格式: 1.最少的代码 <audio src="song.o ...
- python ——单下划线(约定)
命名规则: 通常使用小写单词,必要时用下划线分隔增加可读性. 使用一个前导下划线仅用于不打算作为类的公共接口的内部方法和实例变量. Python不强制要求这样; 它取决于程序员是否遵守这个约定. 使用 ...
- sed `grep` 查找并替换
sed "s/libletvwatermark/libletv_watermark/" `grep -rl libletvwatermark` grep [options] 3.主 ...
- Oracle 时间 MM-dd形式转换
SELECT TO_CHAR( SYSDATE,'MM-dd') AS beginTime,TO_CHAR( TO_DATE(MAX(C.SUBSCRIBE_DATE),'YYYY-MM-dd'),' ...
- MyISAM和InnoDB存储引擎的差别
1.MyISAM不支持事务处理等高级处理,而InnoDB支持. 2.MyISAM强调的是性能,速度更快,而InnoDB提供事务支持以及外键等高级数据库功能. 3.MyISAM读性能比InnoDB强非常 ...