Таймеры C ++ в Unix - PullRequest
       11

Таймеры C ++ в Unix

3 голосов
/ 03 августа 2009

У нас есть API, который обрабатывает таймеры событий. Этот API говорит, что он использует обратные вызовы ОС для обработки событий по времени (очевидно, используя select ()).

API запрашивает этот порядок выполнения: читаемые события записываемые события таймер событий

Это работает путем создания точки для объекта Timer, но передачей функции create обратного вызова функции:

Что-то в этом роде:

Timer* theTimer =  Timer::Event::create(timeInterval,&Thisclass::FunctionName);  

Мне было интересно, как это работает?
Операционная система обрабатывает сам таймер, и когда он видит, что он срабатывает, как он фактически вызывает обратный вызов? Работает ли обратный вызов в отдельном потоке выполнения?

Когда я помещаю вызов pthread_self () в функцию обратного вызова (Thisclass :: FunctionName), кажется, что он имеет тот же идентификатор потока, что и поток, в котором создается theTimer! (Очень смущен этим)

Также: что означает этот список приоритетов выше? Что такое записываемое событие против читаемого события против события таймера?

Любое объяснение использования select () в этом сценарии также приветствуется.

Спасибо!

Ответы [ 5 ]

2 голосов
/ 03 августа 2009

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

Вы должны прочитать о select и poll - они очень удобны. Общий термин IO demultiplexing .

2 голосов
/ 03 августа 2009

Доступное для чтения событие означает, что данные доступны для чтения по определенному дескриптору файла без блокировки, а доступное для записи событие означает, что вы можете записать в определенный дескриптор файла без блокировки. Они чаще всего используются с розетками и трубами. Подробнее см. На странице руководства select().

Событие таймера означает, что срок действия ранее созданного таймера истек. Если библиотека использует select() или poll(), сама библиотека должна отслеживать таймеры, так как эти функции принимают один тайм-аут. Библиотека должна рассчитать время, оставшееся до истечения первого таймера, и использовать его для параметра времени ожидания. Другой подход заключается в использовании timer_create() или более старого варианта, например setitimer() или alarm(), для получения уведомления с помощью сигнала.

Вы можете определить, какой механизм используется на уровне ОС, используя такой инструмент, как strace (Linux) или truss (Solaris). Эти инструменты отслеживают фактические системные вызовы, выполняемые программой.

1 голос
/ 03 августа 2009

Вполне вероятно, что есть фреймворк, который работает с типичным основным циклом, движущей силой основного цикла является вызов select.

select позволяет подождать, пока файловый дескриптор станет читаемым или доступным для записи (или «исключение» в файловом дескрипторе) или истечет время ожидания. Я предполагаю, что библиотека также позволит вам регистрировать обратные вызовы для выполнения асинхронного ввода-вывода, если это библиотека с графическим интерфейсом, она получит события с низким примитивным графическим интерфейсом через файловый дескриптор в Unix.

Чтобы реализовать обратные вызовы таймера в таком цикле, вы просто сохраняете приоритетную очередь таймеров и обрабатывает их при выбранных таймаутах или событиях файлового дескриптора.

Приоритет означает, что он обрабатывает файл ввода-вывода до того, как таймеры, которые сами по себе занимают время, могут привести к обновлениям графического интерфейса, которые в конечном итоге приводят к запуску обработчиков событий графического интерфейса пользователя или другим задачам, тратящим время на обслуживание ввода-вывода.

Библиотека более или менее делает

for(;;) {
  timeout = calculate_min_timeout();
  ret = select(...,timeout); //wait for a timeout event or filedescriptor events
  if(ret > 0) {
    process_readable_descriptors();
    process_writable_descriptors();
  }
  process_timer_queue();  //scan through a timer priority queue and invoke callbacks
}  
1 голос
/ 03 августа 2009

По предположению, вызов create () где-то хранит указатель на функцию. Затем, когда таймер отключается, он вызывает функцию, указанную вами с помощью этого указателя. Но так как это не стандартная функция C ++, вы должны действительно прочитать документы или посмотреть источник, чтобы узнать наверняка.

Что касается других ваших вопросов, я не вижу упоминания о списке приоритетов, а select () является своего рода мультиплексором событий общего назначения.

0 голосов
/ 03 августа 2009

Из-за того, что идентификатор потока внутри обратного вызова таймера совпадает с потоком создателя, я думаю, что он реализован каким-то образом с использованием сигналов.

Когда в поток посылается сигнал, состояние потока сохраняется и вызывается обработчик сигнала, который затем вызывает обратный вызов события. Таким образом, обработчик вызывается в потоке создателя, который прерывается до тех пор, пока обработчик сигнала не вернется.

Возможно, другой поток ожидает всех таймеров, используя select (), и, если таймер истекает, он отправляет сигнал в поток, в котором создан таймер с истекшим сроком.

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