【问题标题】:Current line of code executed by the CPU at a particular point of timeCPU 在特定时间点执行的当前代码行
【发布时间】:2014-02-25 06:05:16
【问题描述】:

我正在用 Objective-C 为 OSX 编写一个应用程序。它是一个多线程应用程序。一个特定线程执行一项工作(捕获屏幕,在 TCP 套接字中写入数据)并休眠 200 毫秒。它醒来并再次执行相同的工作。这将持续运行,直到程序退出。还有另一个线程从 TCP 套接字读取数据。主线程只显示 UI。

当我连续运行该程序一段时间后(大约 2-3 分钟后),第一个线程的 200 毫秒睡眠时间急剧增加到 5 秒或 10 秒。我知道,当另一个线程运行时,第一个线程的睡眠时间可能会延长。我在第二个线程中添加了多个日志打印。看来我的第二个线程没有阻塞 CPU。

当睡眠时间持续较长时间时,我想知道除了我的第一个线程之外,CPU 执行了哪一行代码。 是否可以知道 CPU 在特定时间点执行的当前代码行?这将有助于我调试问题。

更新:

为了缩小范围,我创建了一个简单的程序,它每 200 毫秒打印一个整数(自动递增)。即使在这个简单的程序中,问题也是可重现的。大约 300-400 次迭代后,方法调用时间增加到约 10 秒(即,整数不是每 200 毫秒打印一次。它在每次约 10 秒后打印)

#import "AppDelegate.h"

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    Screen* screen = [[Screen alloc] init];
    [NSThread detachNewThreadSelector:@selector(firstMethod) toTarget:screen withObject:nil];
}

@end

------------------------------------
#import <Foundation/Foundation.h>

@interface Screen : NSObject

-(void) firstMethod;
-(void) secondMethod;

@end

----------------------------
#import "Screen.h"

@implementation Screen
int i=0;
dispatch_queue_t another_queue;

-(Screen*) init {
    self = [super init];
    if (self) {
        another_queue = dispatch_queue_create("com.test.timer", NULL);
    }
    return self;
}


-(void) firstMethod {
    i++;
    NSLog(@"i value : %d",i);
    [self secondMethod];
}

-(void) secondMethod {
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC);
    dispatch_after(popTime, another_queue, ^(void){
        [self firstMethod];
    });
}

@end

【问题讨论】:

  • 对于睡眠,我使用了 [NSThread sleepForTimeInterval:] 我也尝试了 dispatch_after() ,结果相同。
  • 您可以使用trace(1) 从您的应用程序中获取此类信息,更简单的是,您可以使用 Instruments 来获取它。也就是说,您可能应该使用适当的计时器而不是正在休眠的线程来执行此操作。
  • @JasonCoco,1. 我假设 trace(1) 必须插入到我的代码中。我将在我的代码中的哪里添加这一行?当线程休眠时,我不知道正在执行的行(而不是阻塞 CPU)。 2.我试过Instruments,当线程休眠时,CPU变为0%,我不明白这是什么意思。这是否意味着我的线程正在等待一些资源? 3. 为了避免睡眠,我什至尝试了 dispatch_after()。我也得到了相同的结果(再次执行作业之前的时间延长)。
  • 不,您不必插入它,它是一个实用程序。归根结底,它是 Instruments 使用的实用程序。有关详细信息,请参阅命令行上的 man trace。我认为你应该运行 Instruments。尝试从 System Trace 模板或 MultiCore 模板开始。这将为您提供所有处理器事件,包括系统陷阱、线程上下文切换、GCD 信息、调度程序信息等
  • 另外,你永远不应该休眠你的线程。调度程序在那里不做任何保证,并且可能会用这种模式做一些奇怪的事情。你应该使用计时器。有很多选择。您可以在 Foundation 中使用 NSTimer,在运行循环中安排 CoreFoundation 中的计时器,使用 GCD 计时器源,或使用超低级别的 kevent 计时器,甚至使用它与您的套接字多路复用并在单个线程上运行所有内容。但是,无论您选择什么,我都强烈建议您放弃睡眠/等待策略。

标签: objective-c multithreading macos


【解决方案1】:

正如您所描述的那样,“CPU 执行的当前代码行”在大多数情况下将是“无”,即。 CPU 使用率确实为 0%。如果一个 GUI 线程实际上没有处理鼠标/KB 输入,而其他线程正在等待网络数据或休眠,则什么都不会发生,也没有需要执行的代码,因此不需要 CPU。

Sleep() 本质上没有任何问题。调用它的线程将被阻塞,直到间隔到期,由内核中的共享计时器队列确定。不需要其他线程/计时器/任何东西,并且调用者的调用/返回上下文被保留(与使用显式计时器不同)。在经过的时间间隔加上一些 ms 计时器抖动之后,睡眠线程变得准备就绪(不一定正在运行,如 cmets 中其他人所描述的那样)。通常,一直在等待某事的线程(睡眠定时器、I/O 或线程间同步)在准备就绪时都会获得临时优先级提升,并且可能会设置为相当快地运行,除非您的盒子是因运行更高优先级的线程而过载,(如果 CPU 使用率在睡眠期间降至 0,则似乎不是这样)。

“第一个线程的 200 毫秒睡眠时间急剧增加到 5 秒或 10 秒”的明显问题不太可能是 Sleep() 调用本身的一些工件。更有可能的是,传递的时间间隔实际上已被某些错误破坏,或者不是 Sleep() 调用产生了额外的延迟。也许您的网络发送调用因为服务器或链接很慢并且网络缓冲区已满而长时间阻塞?

【讨论】:

  • 亲爱的 Martin James,我已经编辑了我的原始帖子并添加了更多观察结果。你能检查一下吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 2022-01-16
  • 2016-12-24
相关资源
最近更新 更多