Работаем с таймерами.

До появления вот этой темы на РСДНе я как-то не предавал особого значения таймерам в Mac OS X. Ну есть они и есть, как будет нужно так разберусь. Но как оказалось, стандартных POSIX вызовов, таких как timer_create/timer_delete у нас нет, а то что есть не всегда подходит.

Хорошенько поковырявшись в документации я пришел к следующему выводу. Всего доступны 3 способа работы с таймерами, дающие приблизительно одинаковый эффект:

  • NSTimer из Foundation;
  • RunLoop из CoreFoundation;
  • Таймеры из Mach. Хотя у меня данный пункт вызвал некоторые трудности.

Так что по порядку, с краткими иллюстрациями.

NSTimer из Foundation

Самый простой и наиболее кошерный способ. Подходит для всех, кто не боится использовать Objective-C. Документация к NSTimerподробна и содержит кучу примеров.

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1     target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];

NSRunLoop *loop = [NSRunLoop currentRunLoop];[loop addTimer:timer forMode:NSDefaultRunLoopMode];

time_t startTime, endTime;time( &startTime );

while (count <= 10 )    [loop runMode:NSDefaultRunLoopMode         beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];

time( &endTime );

printf( "Time:t%dnCount:t%dn", (int)(endTime - startTime), count );

Тут, по моему, даже писать особо не о чем (да и лень мне )

RunLoop из CoreFoundation

По большому счету, это тоже самое что и использование NSTimer, только из Си. Наиболее интересная документация называется CFRunLoopTimer Reference, а используется вся эта радость приблизительно так:

int32_t val = 0;CFRunLoopTimerContext context = {};context.info = &val;

CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,     CFAbsoluteTimeGetCurrent(), 0.1, 0, 0, RunLoopCallBack, &context);

if( timer )    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);

time_t starttime, endtime;

time( &starttime );

while (val <= 10 )    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, false time( &endtime );

printf( "Time:t%dnCount:t%dn", (int)(endtime - starttime), val );

Я конечно понимаю, что это все индивидуально, но лично мне вариант с использованием CFRunLoopTimer нравится больше. Лаконичнее и проще.

Mach таймеры

А вот тут я несколько запутался. Толи я неправильно использовал clock_alarm, толи еще что-то, но если убрать закомментированную проверку в примере ниже, то появится сообщение об ошибке. Тем не менее, если ошибку игнорировать все вроде даже работает.

current_task = mach_task_self();

kr = host_get_clock_service( mach_host_self(), SYSTEM_CLOCK, &clk_server );CHK_KR_ERROR(kr, "host_get_clock_service");

mach_timespec_t alarm_time;alarm_time.tv_sec = 0;alarm_time.tv_nsec = 50000000;clock_reply_t alarm_port;

kr = mach_port_allocate( current_task, MACH_PORT_RIGHT_RECEIVE, &alarm_port );CHK_KR_ERROR(kr, "mach_port_allocate");

time( &starttime );int val = 0;while( 10 >= val ){    kr = clock_alarm( clk_server, TIME_RELATIVE, alarm_time, alarm_port );    CHK_KR_ERROR(kr, "clock_alarm");

    kr = mach_msg( &header, MACH_RCV_MSG, 0, header.msgh_size, alarm_port,                                        MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL );// CHK_KR_ERROR(kr, "mach_msg");    ++val;}time( &endtime );

printf( "Time:t%dnCount:t%dn", (int)(endtime - starttime), val );

Код целиком можно скачать тут.

Leave a Reply