线程

来源:互联网 发布:淘宝怎么删自己的评论 编辑:程序博客网 时间:2024/06/05 22:44

线程:

线程是操作系统中独有的

在早期的单片机等是没有的

 

NSThread   NSOperation  dispatch_queue_t

这三个 就是形式不一样的线程

官方推荐用GCD  所以  多用GCD

 

 

IOS中

主线程在main函数中创建

子线程需要手动创建

 

编码过程中的规则:

主线程不允许阻塞   主要负责UI交互

子线程主要负责数据处理 (数据库操作 图像处理  音视频压缩)

 

线程开销资源有系统自动回收

 

子线程并发  同时执行时无序的

 

******

@interface NSObject (NSThreadPerformAdditions)

 

(void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);

创建线程的一种方法  第三个参数 是sel 的参数   

自动执行

 

 

*****

@interface NSThread NSObject  

线程类

 

(void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;

第二种创建线程的方法

自动执行

 

 

(id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument NS_AVAILABLE(10_5, 2_0);

第三种创建线程的方法

需要手动启动执行

 

(void)start NS_AVAILABLE(10_5, 2_0);

开始线程

 

(void)cancel NS_AVAILABLE(10_5, 2_0);

取消线程

 

(NSString *)name NS_AVAILABLE(10_5, 2_0);

给线程打标签  取名字

 

这个线程类中有很多属性和方法  基本上望文生义

 

 

*******

线程带来了很多好处 也有一定的问题:

经典问题:——售票问题:

解决方法:

资源锁  枷锁后就会正常了  一下是通常写法

while (1) {

        [_lock lock];

        if (sum{

            [NSThread sleepForTimeInterval:1.0];

            sum--;

            count 10-sum;

            NSLog(@"总票数:%d 售出:%d"sum, count);

        else {

            break;

        }

        [_lock unlock];

        

    }

 

@interface NSLock NSObject <</SPAN>NSLocking

  同时只能允许一个线程访问该资源

先到先锁

nonatomic  不加锁的  可以提高访问速度

atomic 加锁的  以牺牲系统性能为代价的获取资源安全

 

(void)lock;

(void)unlock;

成对出现

 

@interface NSCondition NSObject <</SPAN>NSLocking

条件锁

(void)lock;

(void)unlock;

(void)signal;

(void)wait;

 

A线程等B线程访问之后再访问

发信号 B等待  以下是通常写法

(void)doSomethingA

{

    [_con lock];

    NSLog(@"start A");

    [NSThread sleepForTimeInterval:2.0];

    NSLog(@"end A");

    [_con signal];

    [_con unlock];

}

(void)doSomethingB

{

    [_con lock];

    NSLog(@"start B");

    NSLog(@"end B");

    [_con wait];

    [_con unlock];

}

 

******

@synchronized(xx)

加锁

 

 

****

RunLoop

@interface NSRunLoop NSObject 

每一个线程都会有RunLoop事件循环

RunLoop会套一个自动释放池

Runloop会让线程有活干就干活   没活就休息  让出CPU时间片

 

***

事件在IOS中分为两大类

事件源:用户输入+定时器

***

 

在三个地方会用到RunLoop(三个场景)

用户的异步滚动事件与定时器   一般写法是不能共存的  要想共存 需要用RunLoop

RunLoop有两种常用mode  默认模式是不支持共存的

CommomcModes是支持共存的

 

(NSRunLoop *)currentRunLoop;

 

(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;

 

(void)addTimer:(NSTimer *)timer forMode:(NSString *)mode;

 

FOUNDATION_EXPORT NSString const NSDefaultRunLoopMode;

FOUNDATION_EXPORT NSString const NSRunLoopCommonModes NS_AVAILABLE(10_5, 2_0);

asi默认的是第二个mode

 

滚动事件与异步请求

 

NSURLRequest *request [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dl_dir.qq.com/qqfile/qq/QQforMac/QQ_V2.4.1.dmg"]];

[NSURLConnection connectionWithRequest:request delegate:self];

当程序正常运行时  如果有异步请求  当发生滚动事件时(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

这个方法就会暂停(就是下载暂停)  等到滚动事件结束后就会继续这个方法

这样的话 用户体验是很不好的

 

若想共存写法:

NSURLConnection *con [[NSURLConnection allocinitWithRequest:request delegate:self startImmediately:NO];

[con scheduleInRunLoop:[NSRunLoop currentRunLoopforMode:NSRunLoopCommonModes];

    [con start];

 

分析:

(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately NS_AVAILABLE(10_5, 2_0);

第三个参数一般要写NO

因为

YES if the connection should being loading data immediately, otherwise NOIf you pass NOthe connection is not scheduled with run loop. You can then schedule the connection in the run loop and mode of your choice by calling scheduleInRunLoop:forMode:.

 

(void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode NS_AVAILABLE(10_5, 2_0);

这个是NSURLConnection的方法  就是在RunLoop中与用户交互事件共存

 

在子线程中使用异步下载,那么子线程结束后会结束子线程中的所有异步下载。

解决办法

[[NSRunLoop currentRunLooprunMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

在子线程中跑一个while  while中执行RunLoop  直到完成异步下载时结束while循环  即结束子线程

while需要退出的标记(bool值)作为退出条件

 

 

***********

使用线程 就可以使用同步下载方法  因为不会阻塞主线程

(id)dataWithContentsOfURL:(NSURL *)url;

同步下载方法

 

__unused NSData *data [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://dl_dir.qq.com/qqfile/qq/QQforMac/QQ_V2.4.1.dmg"]];

同步下载

如果放到主线程中就会阻塞

放到子线程中就没关系

 

***

编码规范:

不要在子线程中给UI赋值

在子线程退出时  才会刷新UI

所以要在主线程中给UI赋值

 

***

__unused

用这个关键字  就可以让没用过的变量不被警告

***

 

***

线程之间通讯:

(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

通知主线程执行SEL

(void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

通知指定线程thr,执行SEL

如果传参比较多 可以直接传个字典过去。

 

****

 

 

 

********

线程池:

 

@interface NSOperationQueue NSObject 

线程池(队列)

 

@interface NSOperation NSObject 

一个线程

 

线程池用法:

创建一个类  MyThread: NSOperation

如果不继承  就无法添加到线程池中

在该类中重写  -(void)main()

每一个main就相当于一个独立的代码段  即一个线程

是线程的入口函数

将对象放到线程池中 就会自动启动线程(执行线程中 的main方法),线程池中的线程是并发执行的,顺序随机的

 

****

 

@interface NSOperationQueue NSObject

(void)addOperation:(NSOperation *)op;

(void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

添加线程

(void)setSuspended:(BOOL)b;

(BOOL)isSuspended;

挂起

 

@interface NSOperation NSObject {

里面的 方法都是望文生义的

 

 

**************

GCD

多线程解决方案

纯C接口的封装

 

按种类来分分两种:

①串行队列

(在这个队列里一般做UI处理  队列中的任务依次单个执行)

②并行队列

(在这个队列中跟一般做数据处理  队列中的任务并发无序执行)

 

 

细分主要是3种队列:

①②是系统自带两个队列

①串行队列dispatch_get_main_queue();

可以用来回归主线程

(还有一个方法也能回归主线程:performSelectorOnMainThread)

(当触发几个事件的时候 也是可以触发主线程的:触摸  晃动 远程控制)

(在这个队列里一般做UI处理)

②并行队列dispatch_get_global_queue(优先级, 待扩展)

(在这个队列中跟一般做数据处理)

③自己创建的队列dispatch_queue_create(队列名字, 队列种类)

 

 

 

CocoaLigature1 例:

dispatch_queue_t _mainQueue;

dispatch_queue_t _globalQueue;

dispatch_queue_t _customQueue;

_mainQueue dispatch_get_main_queue();

        _globalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT0);

        _customQueue dispatch_queue_create("MyQueue"DISPATCH_QUEUE_CONCURRENT);

 

 

 

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

相当于创建一个线程

 

 

例:

dispatch_async(_globalQueue^{

        NSData *data [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img.app.d1cm.com/news/img/201312021616153719.jpg"]];

        dispatch_async(_mainQueue^{

            iv.image [UIImage imageWithData:data];

        });

    });

 

 

GCD可以无限制的嵌套

GCD可以分组

dispatch_group_t

 

dispatch_group_t

dispatch_group_create(void);

创建dispatch_group_t

 

void

dispatch_group_async(dispatch_group_t group,

dispatch_queue_t queue,

dispatch_block_t block);

同步执行

 

dispatch_group_notify(dispatch_group_t group,

dispatch_queue_t queue,

dispatch_block_t block);

group的其他queue都执行完了 才执行这个queue

这个方法 只能执行一次

 

void

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

分割线队列  类似分割线的功能

分割线上边的队列并发  然后执行这个queue  然后执行分割线后边的队列

可以无限次画这个分割线队列

 

dispatch_once_t

单例

 

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

        

 

0 0
原创粉丝点击