iOS线程While-True死循环会发生什么

一、在工作的代码有一段while-True轮训的逻辑,循环中主要的工作是阻塞的IO

  代码大概如下:

1
2
3
4
5
6
7
8
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    while (YES) {
         
        NSLog(@"CPU %f", cpu_usage());
         
        [NSThread sleepForTimeInterval:1];
    }
});

  正常的时候,因为io的阻塞关系,线程会在io的方法处等待返回,偶然发现特定情况下,阻塞io方法直接放回错误,这样会不停的进行死循环,因此我想看看死循环会带来什么问题

  我写了下面的代码

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
//  ViewController.m
//  TestCPU
//
//  Created by lilun on 2019/3/20.
//  Copyright © 2019年 lilun. All rights reserved.
//
 
#import "ViewController.h"
#import <mach/mach.h>
#import <assert.h>
 
float cpu_usage()
{
    kern_return_t kr;
    task_info_data_t tinfo;
    mach_msg_type_number_t task_info_count;
     
    task_info_count = TASK_INFO_MAX;
    kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
     
    task_basic_info_t      basic_info;
    thread_array_t         thread_list;
    mach_msg_type_number_t thread_count;
     
    thread_info_data_t     thinfo;
    mach_msg_type_number_t thread_info_count;
     
    thread_basic_info_t basic_info_th;
    uint32_t stat_thread = 0; // Mach threads
     
    basic_info = (task_basic_info_t)tinfo;
     
    // get threads in the task
    kr = task_threads(mach_task_self(), &thread_list, &thread_count);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    if (thread_count > 0)
        stat_thread += thread_count;
     
    long tot_sec = 0;
    long tot_usec = 0;
    float tot_cpu = 0;
    int j;
     
    for (j = 0; j < (int)thread_count; j++)
    {
        thread_info_count = THREAD_INFO_MAX;
        kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
                         (thread_info_t)thinfo, &thread_info_count);
        if (kr != KERN_SUCCESS) {
            return -1;
        }
         
        basic_info_th = (thread_basic_info_t)thinfo;
         
        if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
            tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            tot_usec = tot_usec + basic_info_th->user_time.microseconds + basic_info_th->system_time.microseconds;
            tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
        }
         
    } // for each thread
     
    kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
    assert(kr == KERN_SUCCESS);
     
    return tot_cpu;
}
 
 
@interface ViewController ()
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.3
     
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self runOneThread:1];
        //    [self runOneThread:2];
        //    [self runOneThread:3];
        //    [self runOneThread:4];
    });
     
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 100)];
    label.textColor = [UIColor redColor];
    label.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:label];
    label.center = self.view.center;
    label.tag = 1234;
     
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES) {
             
            NSLog(@"CPU %f", cpu_usage());
             
            dispatch_async(dispatch_get_main_queue(), ^{
                UILabel *label = [self.view viewWithTag:1234];
                label.text = [NSString stringWithFormat:@"CPU %f", cpu_usage()];
            });
             
            [NSThread sleepForTimeInterval:1];
        }
    });
     
 
     
 
}
 
 
- (void)runOneThread:(NSInteger)i
{
     
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
         
        while (YES) {
             NSLog(@"run thread %ld", i);
        }
    });
     
}
 
 
@end

  上面的代码如果运行在模拟器的时候,大概4核的cpu(400%)会占据40%的CPU,还不是很多,貌似模拟器的CPU占用会限制。

    此时电脑风扇会呼呼转。

 

  上面的代码是真机调试的状态下,会出现调试器卡死,Xcode无反应,必须拔掉USB线来中断调试。

    猜测原因是循环输出的log占满了USB通信的带宽,导致调试信息无法传递到Xcode上。或者是调试线程因为工作线程导致无法工作正常

 

  如果是非调试模式下面,大概会占用98%(以上的方法测试出来)的CPU,机器会发烫。

    应该极力避免出现死循环的情况,即使是在子线程中出现的死循环。

 

总结:

  死循环在子线程也是不能出现的,任何方法一定要限制好频率。

  NSlog会产生系统中断,频繁的系统中断也会导致性能低下。  

    

  

posted @   兜兜有糖的博客  阅读(1655)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示