pthread_cond_timedwait_relative_np比它应该等待100ms

时间:2018-05-15 03:42:02

标签: ios xcode pthreads

我遇到了pthread_cond_timedwait_relative_np的一些我无法解释的行为,我希望有人知道发生了什么。

以下代码示例在100 ms后超时。

struct timespec rtime1, rtime2, ts;
int ret;
uint32_t timeout = 100;
get_monotonic_time(&rtime1);
ts.tv_sec = timeout / 1000L;
ts.tv_nsec = (timeout % 1000L) * 1000000L;
printf("relative_np %ld\n", timeout);
ret = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
if (ret == ETIMEDOUT) {
 get_monotonic_time(&rtime2);
 ts.tv_sec = rtime2.tv_sec - rtime1.tv_sec;
 ts.tv_nsec = rtime2.tv_nsec - rtime1.tv_nsec;
 if (ts.tv_nsec < 0) {
   ts.tv_sec--;
   ts.tv_nsec += 1000000000L;
 }
 printf("waited %ld\n", ts.tv_sec * 1000L + ts.tv_nsec / 1000000L);
 return SYS_ARCH_TIMEOUT;
}

在iPhone 6s,Xcode中的iOS 10模拟器上打印

relative_np 100
waited 100

但是在iPhone 5s,iOS 9模拟器上,它打印

relative_np 100
waited 200

事实上,它始终等待它应该的两倍。什么可以解释这一点,有没有办法解决它?是否应将超时设置为预期值的一半以进行更正?是否有原因从iOS更改为另一个?

编辑:我已经想到了更多这个谜题,虽然我可能比以前更加困惑。

首先,它不是两倍长,它比它应该长100毫秒。就是这样,我测试的东西等了100ms。但如果我等待5ms,我会看到等待105ms。

其次,使用相同的模拟器(设备和iOS版本),我不会在一个全新的项目中得到这种行为 - 等待时间恰当。这对我来说,这是由我项目中发生的事情引起的。除了,当我在现有项目中创建一个新的测试套件而不包括我的项目头文件或调用它的任何代码时,它仍然会发生。

这对我来说唯一可行的方法就是如果简单地加载我的项目会导致这种情况?我很难想象尽管如此。

1 个答案:

答案 0 :(得分:0)

事实证明,Xcode的Framework测试程序在测试iOS 9及更低版本时就已破坏。

证明这很容易。只需创建一个新的Cocoa Touch Framework,将部署目标设置为iOS 9,然后添加单元测试。将其粘贴到测试中并运行它。

#import <XCTest/XCTest.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <sys/sysctl.h>

@interface timewait : XCTestCase

@end

@implementation timewait

static void get_monotonic_time(struct timespec *ts)
{
  struct timeval boottime;
  int mib[2] = {CTL_KERN, KERN_BOOTTIME};
  size_t size = sizeof(boottime);
  sysctl(mib, 2, &boottime, &size, NULL, 0);

  struct timeval now;
  gettimeofday(&now, NULL);

  uint64_t now_micro = now.tv_usec + (1000000 * now.tv_sec);
  uint64_t boot_micro = boottime.tv_usec + (1000000 * boottime.tv_sec);
  uint64_t diff_micro = now_micro - boot_micro;

  ts->tv_nsec = (diff_micro % 1000000) * 1000;
  ts->tv_sec = diff_micro / 1000000;
} 

- (void)testTimedWait {
  uint32_t timeout = 5;

  struct timespec rtime1, rtime2, ts;
  int ret;

  for (unsigned int i = 0; i < 100; ++i) {
    get_monotonic_time(&rtime1);

    printf("sleeping for %u\n", timeout);
    [NSThread sleepForTimeInterval:(timeout / 1000.)];
    get_monotonic_time(&rtime2);
    ts.tv_sec = rtime2.tv_sec - rtime1.tv_sec;
    ts.tv_nsec = rtime2.tv_nsec - rtime1.tv_nsec;
    if (ts.tv_nsec < 0) {
      ts.tv_sec--;
      ts.tv_nsec += 1000000000L;
    }
    printf("waited %ld\n", ts.tv_sec * 1000L + ts.tv_nsec / 1000000L);

  }
}
@end

无论你将超时值设置为什么,睡眠似乎持续约100毫秒。针对iOS 10目标运行测试,差异消失。