高度なiOSの多くのスレッド--NSThreadコメント

NSThreadについて

NSThreadアップル公式のオブジェクト指向のオペレーティング・スレッド技術、簡単で便利な、あなたは直接スレッドオブジェクトを操作しますが、独自の制御スレッドのライフサイクルを必要とすることができます。最も一般的に使用される以外の何ものでもありません、平時にはほとんどを使用し[NSThread currentThread]、現在のスレッドを取得します。


NSThreadの使用

図1に示すように、インスタンスの初期化、メソッドとプロパティの例

  • 初期化
   //创建线程
   NSThread *newThread = [[NSThread alloc]initWithTarget:self selector:@selector(demo:) object:@"Thread"]; //或者 NSThread *newThread=[[NSThread alloc]init]; NSThread *newThread= [[NSThread alloc]initWithBlock:^{ NSLog(@"initWithBlock"); }]; 
  • プロパティ
  1. スレッド辞書
/**
每个线程都维护了一个键-值的字典,它可以在线程里面的任何地方被访问。
你可以使用该字典来保存一些信息,这些信息在整个线程的执行过程中都保持不变。
比如,你可以使用它来存储在你的整个线程过程中 Run loop 里面多次迭代的状态信息。
NSThread实例可以使用一下方法
*/
@property (readonly, retain) NSMutableDictionary *threadDictionary; NSMutableDictionary *dict = [thread threadDictionary]; 
  1. 優先順位
@property double threadPriority ; //优先级
  1. スレッドの優先順位
/** NSQualityOfService:
  NSQualityOfServiceUserInteractive:最高优先级,主要用于提供交互UI的操作,比如处理点击事件,绘制图像到屏幕上
  NSQualityOfServiceUserInitiated:次高优先级,主要用于执行需要立即返回的任务
  NSQualityOfServiceDefault:默认优先级,当没有设置优先级的时候,线程默认优先级
  NSQualityOfServiceUtility:普通优先级,主要用于不需要立即返回的任务
  NSQualityOfServiceBackground:后台优先级,用于完全不紧急的任务
*/
@property NSQualityOfService qualityOfService; 
  1. スレッド名
@property (nullable, copy) NSString *name;
  1. スレッドのスタックサイズの領域を使用し、デフォルトは512Kです
@property NSUInteger stackSize ;
  1. スレッドが実行されています
@property (readonly, getter=isExecuting) BOOL executing;
  1. スレッドの実行が終了
@property (readonly, getter=isFinished) BOOL finished;
  1. スレッドをキャンセルすることができるかどうか
@property (readonly, getter=isCancelled) BOOL cancelled;
  • 方法の例
  1. - (無効)を開始、スレッドを開始
    インスタンス化のスレッドを実行するために、手動で起動する必要があります
    [thread start];
  1. - (BOOL)isMainThread、メインスレッドか
 isMain=[thread isMainThread];
  1. - (無効)のsetName:(NSStringの*)nは、セットのスレッド名
[thread setName=@"The Second Thread"];
  1. - キャンセル(無効);キャンセルのスレッド
[thread cancel];
  1. - (ボイド)主;スレッドエントリ機能
[thread main];
  1. - (ボイド)isExecuting、スレッドを実行するかどうかを決定します
BOOL isRunning=[thread isExecuting];
  1. - (無効)isFinished、スレッドが終了したかどうかを判断します
BOOL isEnd=[thread isFinished];
  1. - (ボイド)isCancelled、スレッドを撤回するかどうかを決定します
isCancel=[thread isCancelled];

2、クラスメソッド

  1. 子スレッドを作成して開始し、実行した後、2つのクラスを作成するには、次の方法に注意して、手動でオープンなし
/**
  block方式
*/
+ (void)detachNewThreadWithBlock:(void (^)(void))block;
/** SEL方式 */ + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument; 
  1. +(ボイド)currentThread、現在のスレッドを取得します。
[NSThread currentThread]
  1. +(BOOL)isMultiThreaded;コードは子スレッドであるかどうか、現在実行中のスレッドを
BOOL isMulti = [NSThread isMultiThreaded];
  1. +(ボイド)sleepUntilDate:(NSDate *)日付、スレッドスリープ時間を指定するために、現在のコード
   [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
  1. +(ボイド)sleepForTimeInterval:(NSTimeInterval)TI、どのように長い眠りに現在のスレッド
    [NSThread sleepForTimeInterval:1.0];
  1. +(ボイド)出口、現在のスレッドを終了します
[NSThread exit];
  1. +(ダブル)threadPriority、現在のスレッドの優先順位を設定します
double dPriority=[NSThread threadPriority];
  1. +(BOOL)setThreadPriority:(ダブル)P、スレッドの優先順位が現在のスケジューリング優先度に設定されている範囲である0.0〜1.0、0.5デフォルト、値が大きいほど、より高い優先度です。
BOOL isSetting=[NSThread setThreadPriority:(0.0~1.0)];
  1. +(NSArrayの*)callStackReturnAddresses;呼び出しスレッドはリターンが関数呼び出しが戻るの仮想アドレスであるレコードのリターンアドレスを、そこにスタックします呼び出し関数の機能を呼び出す必要があり、それがはっきり仮想スレッドの関数呼び出しでありますアレイアドレス
NSArray *addressArray=[NSThread callStackReturnAddresses];
  1. +(にNSArray *)callStackSymbolsリターンデジタル呼ばれるスレッド関数の名前であることを除いて上記と同様の方法、
NSArray* nameNumArray=[NSThread callStackSymbols];

注意:callStackReturnAddressとcallStackSymbolsは、この2つの関数はのNSLogと一緒に使用するスレッドを追跡するための関数呼び出しは、プログラミングとデバッグの重要な手段であることができます


3、暗黙的に作成&スレッド間通信

以下の方法は、NSObjectの(NSThreadPerformAdditions)の分類であり、オブジェクトのすべての継承NSObjectのインスタンスは以下のメソッドを呼び出すことができ

/**
  指定方法在主线程中执行
参数1. SEL 方法
    2.方法参数
    3.是否等待当前执行完毕
    4.指定的Runloop model
*/
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait; // equivalent to the first method with kCFRunLoopCommonModes /** 指定方法在某个线程中执行 参数1. SEL 方法 2.方法参数 3.是否等待当前执行完毕 4.指定的Runloop model */ - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // equivalent to the first method with kCFRunLoopCommonModes /** 指定方法在开启的子线程中执行 参数1. SEL 方法 2.方法参数 */ - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); 

注:私たちは、多くの場合、上記の方法の「スレッド間通信」と呼ばれ、実際に背の高いよりも、少数ではないではない、と複雑な以外の何物でも!

再び注意:いないすべてのバックグラウンドスレッドがUIが間違って行くだろう更新がAppleのUIの更新ステートメントは、UIスレッド(メインスレッド)で実行する必要があります。

図4に示すように、スレッド間のリソースの共有スレッドロック&

プログラムが実行されているマルチスレッドがある場合は、各スレッドは資源が、それは別のスレッドであるため、運用リソースを読み書き同時にCPUスケジューリングプロセスを存在する読み取りおよび書き込みしている、我々はどのスレッド意志最初の識字リソースを保証することはできません、どのスレッドリソースを読み取り、書き込み後。そのため、混乱を防止し、発生するデータエラーを読み書きするために、我々はデータのロックを読み書きする際スレッドする必要があるので、我々は、同じオペレーティング・スレッドを保証することができますロックを解除するには、スレッドの実行が完了した後、一つだけのデータオブジェクトである、他のスレッドすることができますデータオブジェクトのこのオペレーション。NSLock / NSConditionLock / NSRecursiveLock / @Synchronizedスレッド同期動作を実現することができます。

  1. @synchronized
    例に直接:12306我々は列車の切符を販売する例を理解すると信じて
    最初の2つのスレッドを同時にオープンチケット
    self.tickets = 20;
    NSThread *t1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTickets) object:nil]; t1.name = @"售票员A"; [t1 start]; NSThread *t2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTickets) object:nil]; t2.name = @"售票员B"; [t2 start]; 

次に:チケットをロックする方法

- (void)saleTickets{
    while (YES) {
        [NSThread sleepForTimeInterval:1.0]; //互斥锁 -- 保证锁内的代码在同一时间内只有一个线程在执行 @synchronized (self){ //1.判断是否有票 if (self.tickets > 0) { //2.如果有就卖一张 self.tickets --; NSLog(@"还剩%d张票 %@",self.tickets,[NSThread currentThread]); }else{ //3.没有票了提示 NSLog(@"卖完了 %@",[NSThread currentThread]); break; } } } } 
  1. NSLock
    -(BOOL)tryLock;//尝试加锁,成功返回YES ;失败返回NO ,但不会阻塞线程的运行
    -(BOOL)lockBeforeDate:(NSDate *)limit;//在指定的时间以前得到锁。YES:在指定时间之前获得了锁;NO:在指定时间之前没有获得锁。 该线程将被阻塞,直到获得了锁,或者指定时间过期。 - (void)setName:(NSString*)newName//为锁指定一个Name - (NSString*)name//**返回锁指定的**name @property (nullable, copy) NSString *name;线程锁名称 

例えば:

 NSLock* myLock=[[NSLock alloc]init];
NSString *str=@"hello";
[NSThread detachNewThreadWithBlock:^{ [myLock lock]; NSLog(@"%@",str); str=@"world"; [myLock unlock]; }]; [NSThread detachNewThreadWithBlock:^{ [myLock lock]; NSLog(@"%@",str); str=@"变化了"; [myLock unlock]; }]; 

ロックした後、出力解像度は、Hello Worldのであり、出力がロックされていない前に、それは同じ2つのスレッドのhelloを出力します。

  1. NSConditionLockは
    、プロデューサ/コンシューマ・モデルのための典型的な、すなわち一時停止し、ブロック、ロックを取得しないスレッドの場合には、このロックを使用します。
- (instancetype)initWithCondition:(NSInteger)condition;//初始化条件锁
- (void)lockWhenCondition:(NSInteger)condition;//加锁 (条件是:锁空闲,即没被占用;条件成立) - (BOOL)tryLock; //尝试加锁,成功返回TRUE,失败返回FALSE - (BOOL)tryLockWhenCondition:(NSInteger)condition;//在指定条件成立的情况下尝试加锁,成功返回TRUE,失败返回FALSE - (void)unlockWithCondition:(NSInteger)condition;//在指定的条件成立时,解锁 - (BOOL)lockBeforeDate:(NSDate *)limit;//在指定时间前加锁,成功返回TRUE,失败返回FALSE, - (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//条件成立的情况下,在指定时间前加锁,成功返回TRUE,失败返回FALSE, @property (readonly) NSInteger condition;//条件锁的条件 @property (nullable, copy) NSString *name;//条件锁的名称 

例えば:

  NSConditionLock* myCondition=[[NSConditionLock alloc]init];
    [NSThread detachNewThreadWithBlock:^{
        for(int i=0;i<5;i++) { [myCondition lock]; NSLog(@"当前解锁条件:%d",i); sleep(2); [myCondition unlockWithCondition:i]; BOOL isLocked=[myCondition tryLockWhenCondition:2]; if(isLocked) { NSLog(@"加锁成功!!!!!"); [myCondition unlock]; } } }]; 

出力は、ロック待機状態2ロック成功を解除した後の2つの条件。

  1. NSRecursiveLockは、
    このロックは、同じスレッド内で複数回使用することができるが、そのロックを確保し、デッドロックを防ぐために、再帰関数に使用されるバランスを使用してロックを解除します。
- (BOOL)tryLock;//尝试加锁,成功返回TRUE,失败返回FALSE
- (BOOL)lockBeforeDate:(NSDate *)limit;//在指定时间前尝试加锁,成功返回TRUE,失败返回FALSE @property (nullable, copy) NSString *name;//线程锁名称 

使用例:

-(void)initRecycle:(int)value
{
   [myRecursive lock];
   if(value>0)
   {
       NSLog(@"当前的value值:%d",value); sleep(2); [self initRecycle:value-1]; } [myRecursive unlock]; } 

出力:1までのご入ってくる値から、デッドロックはありません


図5に示すように、原子のスレッドセーフアトミック特性

アトミック性質(スレッドセーフ)とアトミックの特性、通常我々は、非アトミック@property宣言オブジェクトのプロパティを使用しますが、それは何を意味するのでしょうか?
我々は、オブジェクトの属性を宣言するときに、デフォルトではAppleが唯一のスレッドが同時に実行できることを保証するために、このプロパティは読み書きするときことを意味し、アトミックです。宣言を使用する原子である場合のメンバ変数は、ゲッター&セッター_メンバ変数は自動的に生成されていないを書き換える場合、典型的には_生成します。実際に呼ばれる原子財産の内部ロックがあり、「スピンロックが。」
まず、「スピンロック」&「ミューテックス、」類似点と相違点を比較して、上記の質問に答えます

  • 共通グラウンド
    スレッドの安全性を保証することができます
  • 異なる点
    ミューテックス:別のスレッドがロックコードを実行している場合は、このスレッドは、開くためにロックを待機し、休眠状態に入りますが、その後、目を覚ます
    スピンロック:スレッドがロックアウトされた場合にロビン方式を、それが死んだ兄となりますロックを待っているが開かれました!

どのようなロック性能を消費している、効率が高くないので、私たちの通常の開発プロセスでは、非アトミック使用します。

@property (strong, nonatomic) NSObject *myNonatomic;
@property (strong, atomic) NSObject *myAtomic; 

上記の説明によると、私たちはmyAtomic setterメソッドとgetterメソッドを書き換えたとき、と結論します

- (void)setMyAtomic:(NSObject *)myAtomic{
      _myAtomic = myAtomic;
}
- (NSObject *)myAtomic{
    return _myAtomic;
}

その後、我々は静的変数を宣言する必要があります_myAtomic

@synthesize myAtomic = _myAtomic;

そうしないとシステムはコンパイル時に_myAtomicを見つけることができません


6、子スレッドを実行ループ

  1. 実行ループの前に興味深いエピソードを紹介した最初の子スレッドは、我々は実行ループを導入し、さらに実行ループのシミュレート
    実行ループの実行サイクルを
    -現在のiOS開発では、以前のiOSの暗黒時代、プログラマーに比べてほとんど少ないです使用
    目的を:するには
    、プログラムが終了していないことを確認する
    イベントをリスニング
    はイベントがスリープにプログラムを作るん
    :モード差別
    NSDefaultRunLoopMode -クロック、ネットワークイベントの
    NSRunLoopCommonModes -ユーザーとの対話を

アナログ実行ループ

void click(int type){ printf("正在运行第%d",type); } int main(int argc, const char * argv[]) { @autoreleasepool { while (YES) { printf("请输入选项 0 表示退出"); int result = -1; scanf("%d",&result); if (result == 0) { printf("程序结束\n"); break; }else{ click(result); } } } return 0; } 
  1. iOS版では、実行ループは、子スレッドではデフォルトで開いている開いていないし、次に実行ループを手動で開いた子スレッドを閉じることはできません。我々は異なるタスクを追加するには、子スレッドの繰り返しを与え、ケース実行ループがオンになっていないときに、子スレッドは、イベントを監視することはできません(正確なサブスレッド実行ループするように)、我々はその後、タスクを追加実行されません。
    私たちは聞かせている場合でも、子スレッドの実行ループが働いて、資源の浪費は、ここで実行ループを制御することができますスレッド子の例に使用OCです:
    まず、実行ループは無限ループがあり、我々は無限ループを作成することができ、その後、缶裁判官を宣言しますプロパティの実行ループサイクルを終了する必要があります
@property (assign, nonatomic, getter=isFinished) BOOL finished; 

子スレッドを作成して、タスクを追加

    NSThread *t = [[NSThread alloc]initWithTarget:self selector:@selector(demo) object:nil]; [t start]; self.finished = NO; [self performSelector:@selector(otherMethod) onThread:t withObject:nil waitUntilDone:NO]; 

最初のタスクで無限ループに参加

- (void)demo{
    NSLog(@"%@",[NSThread currentThread]);
    //在OC中使用比较多的,退出循环的方式 while (!self.isFinished) { [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:.1]]; } NSLog(@"能来吗?"); } 

死のサイクルの終わりを追加するための最後のタスクの終わりに

- (void)otherMethod{
    for (int i = 0; i < 10; i ++) { NSLog(@"%s %@",__FUNCTION__,[NSThread currentThread]); } //让上面方法中的死循环结束 self.finished = YES; } 

おすすめ

転載: www.cnblogs.com/Free-Thinker/p/11413567.html
おすすめ