【发布时间】: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