pthread_cond_timedwait_relative_np ждет на 100 мс дольше, чем следует - PullRequest
0 голосов
/ 15 мая 2018

Я столкнулся с некоторым поведением из pthread_cond_timedwait_relative_np, которое не могу объяснить, и я надеялся, что кто-то может знать, что происходит.

Возьмите следующий пример кода, который истекает через 100 мс.

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, симуляторе iOS 10 в Xcode это печатает

relative_np 100
waited 100

Но на iPhone 5s, симуляторе iOS 9, оно печатает

relative_np 100
waited 200

На самом деле, он постоянно ждет вдвое дольше, чем должен.Что может объяснить это, и есть ли способ это исправить?Следует ли установить таймаут на половину ожидаемого значения, чтобы исправить его?Есть ли причина, по которой он меняется с iOS на другую?

edit: я понял эту головоломку больше, хотя, может быть, я запутался больше, чем когда-либо.

Во-первых, это не в два разадо 100 мс дольше, чем нужно.Просто так получилось, что то, что я тестировал, ждали 100 мс.Но если я жду 5 мс, я вижу ожидание 105 мс.

Во-вторых, используя тот же симулятор (версия устройства и iOS), я не получаю такого поведения в новом проекте - ожидание происходитправильная длинаЭто наводит меня на мысль, что это как-то вызвано тем, что происходит в моем проекте.За исключением случаев, когда я создаю новый набор тестов в моем существующем проекте без включения файла заголовка проекта или вызова какого-либо его кода, это все равно происходит.

Единственный способ, которым это может показаться возможным, - это просто загрузить мойпроект как-то вызывает это?Хотя мне трудно представить, как это возможно.

1 Ответ

0 голосов
/ 17 мая 2018

Оказывается, что тестер 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, и расхождение исчезнет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...