Источники отгрузки

Каждый раз, когда Вы взаимодействуете с базовой системой, Вы должны быть подготовлены к той задаче занять нетривиальное количество времени. Раскритиковывание к ядру или другим системным уровням вовлекает изменение в контекст, который является довольно дорогим по сравнению с вызовами, происходящими в Вашем собственном процессе. В то время как тот запрос обрабатывается, в результате много системных библиотек обеспечивают асинхронные интерфейсы, чтобы позволить Вашему коду подавать запрос к системе и продолжать выполнять другую работу. Центральная Отгрузка основывается на этом общем поведении, позволяя Вам подать Ваш запрос и иметь результаты, сообщившие к Вашим блокам использования кода и очередям отгрузки.

Об источниках отгрузки

Источник отгрузки является основополагающим типом данных, координирующим обработку определенных низкоуровневых системных событий. Центральная Отгрузка поддерживает следующие типы источников отгрузки:

Источники отгрузки заменяют асинхронные функции обратного вызова, обычно использующиеся для обработки связанных с системой событий. При конфигурировании источника отгрузки Вы указываете события, которых Вы хотите следить за развитием и очередь отгрузки и код для использования для обработки тех событий. Можно указать блочные объекты использования кода или функции. Когда мероприятие поступает, источник отгрузки представляет Ваш блок или функцию указанной очереди отгрузки для выполнения.

В отличие от задач, которые Вы представляете очереди вручную, диспетчеризируйте источники, обеспечивают непрерывный источник событий для Вашего приложения. Источник отгрузки остается присоединенным к своей очереди отгрузки, пока Вы не отменяете его явно. В то время как присоединено, это представляет свой связанный код задачи очереди отгрузки каждый раз, когда соответствующее событие имеет место. Некоторые события, такие как события таймера, имеют место равномерно, но большинство происходит только спорадически, поскольку возникают особые условия. Поэтому источники отгрузки сохраняют свою связанную очередь отгрузки, чтобы препятствовать тому, чтобы он был выпущен преждевременно, в то время как события могут все еще находиться на рассмотрении.

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

Создание источников отгрузки

Создание источника отгрузки включает создание и источник событий и сам источник отгрузки. Источник событий является любыми собственными структурами данных, требуются, чтобы обрабатывать события. Например, для основанного на дескрипторе источника отгрузки необходимо было бы открыть дескриптор, и для основанного на процессе источника необходимо будет получить процесс ID целевой программы. Когда у Вас есть свой источник события, можно тогда создать соответствующий источник отгрузки следующим образом:

  1. Создайте источник отгрузки с помощью dispatch_source_create функция.

  2. Сконфигурируйте источник отгрузки:

  3. Дополнительно присвойте обработчик отмены источнику отгрузки; посмотрите Установку Обработчика Отмены.

  4. Вызовите dispatch_resume функционируйте, чтобы начать обрабатывать события; посмотрите Приостановку и Возобновление Источников Отгрузки.

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

Следующие разделы показывают Вам, как сконфигурировать различные аспекты источника отгрузки. Для подробных примеров, показывающих Вам, как сконфигурировать определенные типы источников отгрузки, посмотрите Исходные Примеры Отгрузки. Для получения дополнительной информации о функциях Вы используете, чтобы создать и сконфигурировать источники отгрузки, видеть Ссылку Grand Central Dispatch (GCD).

Запись и установка обработчика событий

Для обработки событий, сгенерированных источником отгрузки, необходимо определить обработчик событий для обработки тех событий. Обработчик событий является функцией, или блок возражают, что Вы устанавливаете на своем источнике отгрузки с помощью dispatch_source_set_event_handler или dispatch_source_set_event_handler_f функция. Когда событие поступает, источник отгрузки представляет Ваш обработчик событий назначенной очереди отгрузки для обработки.

Организация Вашего обработчика событий ответственна за обработку любых поступающих событий. Если Ваш обработчик событий уже ставится в очередь и ожидающий для обработки события, когда новое событие поступает, источник отгрузки объединяет эти два события. Обработчик событий обычно видит информацию только для нового события, но в зависимости от типа источника отгрузки это может также быть в состоянии получить информацию о других событиях, произошедших и объединенных. Если один или несколько новые события поступают после того, как обработчик событий начал выполняться, источник отгрузки содержит на те события, пока обработчик текущего события не закончил выполняться. В той точке это представляет обработчик событий очереди снова с новыми событиями.

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

// Block-based event handler
void (^dispatch_block_t)(void)
 
// Function-based event handler
void (*dispatch_function_t)(void *)

В Вашем обработчике событий можно получить информацию о данном событии из самого источника отгрузки. Несмотря на то, что основанные на функции обработчики событий передаются указатель на источник отгрузки в качестве параметра, основанные на блоке обработчики событий должны получить тот указатель сами. Можно сделать это для блоков путем ссылки на переменную, содержащую источник отгрузки обычно. Например, следующий фрагмент кода получает source переменная, объявляющаяся вне объема блока.

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
                                 myDescriptor, 0, myQueue);
dispatch_source_set_event_handler(source, ^{
   // Get some data from the source variable, which is captured
   // from the parent context.
   size_t estimated = dispatch_source_get_data(source);
 
   // Continue reading the descriptor...
});
dispatch_resume(source);

Получение переменных в блоке обычно делается для обеспечения большей гибкости и динамизма. Конечно, полученные переменные только для чтения в блоке по умолчанию. Несмотря на то, что блочная функция предоставляет поддержку для изменения полученных переменных при определенных обстоятельствах, Вы не должны пытаться сделать так в конечном счете обработчики, связанные с источником отгрузки. Источники отгрузки всегда выполняют свои обработчики событий асинхронно, таким образом, объема определения любых переменных, которые Вы получили, вероятно, не стало к тому времени, когда Ваш обработчик событий выполняется. Для получения дополнительной информации о том, как получить и использовать переменные в блоках, посмотрите, что Блоки Программируют Темы.

Таблица 4-1 перечисляет функции, которые можно вызвать от кода обработчика событий для получения информации о событии.

Табличные 4-1  данные Получения из источника отгрузки

Функция

Описание

dispatch_source_get_handle

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

Для источника отгрузки дескриптора эта функция возвращается int введите содержащий дескриптор, связанный с источником отгрузки.

Для сигнального источника отгрузки эта функция возвращается int введите содержащий сигнальное число для нового события.

Для источника отгрузки процесса эта функция возвращает a pid_t структура данных для контролируемого процесса.

Для источника отгрузки порта Маха эта функция возвращает a mach_port_t структура данных.

Для других источников отгрузки значение, возвращенное этой функцией, не определено.

dispatch_source_get_data

Эта функция возвращает любые незаконченные данные, связанные с событием.

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

Поскольку дескриптор диспетчеризирует источник, пишущий данные в файл, эта функция возвращает положительное целое число, если пространство доступно для записи.

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

Для источника отгрузки процесса эта функция возвращает постоянное указание типа произошедшего события. Для списка констант посмотрите dispatch_source_proc_flags_t перечислимый тип.

Для источника отгрузки порта Маха эта функция возвращает постоянное указание типа произошедшего события. Для списка констант посмотрите dispatch_source_machport_flags_t перечислимый тип.

Для пользовательского источника отгрузки эта функция возвращает новое значение данных, создаваемое из существующих данных, и новые данные передали dispatch_source_merge_data функция.

dispatch_source_get_mask

Эта функция возвращает флаги события, использовавшиеся для создания источника отгрузки.

Для источника отгрузки процесса эта функция возвращает маску событий, которые получает источник отгрузки. Для списка констант посмотрите dispatch_source_proc_flags_t перечислимый тип.

Для источника отгрузки порта Маха с отправляют права, эта функция возвращает маску желаемых событий. Для списка констант посмотрите dispatch_source_mach_send_flags_t перечислимый тип.

Для пользовательского источника отгрузки OR возвращается эта функция, маска раньше объединяла значения данных.

Для некоторых примеров того, как записать и установить обработчики событий для определенных типов источников отгрузки, посмотрите Исходные Примеры Отгрузки.

Установка обработчика отмены

Обработчики отмены используются для очистки источника отгрузки, прежде чем он будет выпущен. Для большинства типов источников отгрузки обработчики отмены являются дополнительными и только необходимыми, если у Вас есть некоторые пользовательские способы поведения, связанные к источнику отгрузки, который также должен быть обновлен. Для источников отгрузки, использующих дескриптор или порт Маха, однако, необходимо обеспечить обработчик отмены, чтобы закрыть дескриптор или выпустить порт Маха. Отказ сделать так может привести к тонким ошибкам в Вашем коде, следующем из тех структур, снова используемых непреднамеренно Вашим кодом или другими частями системы.

Можно установить обработчик отмены в любое время, но обычно Вы делали бы так при создании источника отгрузки. Вы устанавливаете обработчик отмены с помощью dispatch_source_set_cancel_handler или dispatch_source_set_cancel_handler_f функция, в зависимости от того, хотите ли Вы использовать блочный объект или функцию в Вашей реализации. Следующий пример показывает простой обработчик отмены, закрывающий дескриптор, открытый для источника отгрузки. fd переменная является полученной переменной, содержащей дескриптор.

dispatch_source_set_cancel_handler(mySource, ^{
   close(fd); // Close a file descriptor opened earlier.
});

Для наблюдения полного примера кода для источника отгрузки, использующего обработчик отмены посмотрите Данные Чтения из Дескриптора.

Изменение очереди Target

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

Изменение очереди источника отгрузки является асинхронной работой, и источник отгрузки прилагает все усилия для внесения изменения как можно быстрее. Если обработчик событий уже ставится в очередь и ожидающий, чтобы быть обработанным, он выполняется на предыдущей очереди. Однако другие события, поступающие примерно во время Вы, вносят изменение, мог быть обработан на любой очереди.

Соединение пользовательских данных с источником отгрузки

Как много других типов данных на Центральной Отгрузке, можно использовать dispatch_set_context функционируйте для соединения пользовательских данных с источником отгрузки. Можно использовать указатель контекста, чтобы хранить любые данные обработчик событий должен обработать события. Если Вы действительно храните какие-либо пользовательские данные в указателе контекста, необходимо также установить обработчик отмены (как описано в Установке Обработчика Отмены) для выпуска тех данных, когда больше не необходим источник отгрузки.

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

Управление памятью для источников отгрузки

Как другие объекты отгрузки, источники отгрузки являются ссылочными считаемыми типами данных. Источник отгрузки имеет начальный подсчет ссылок 1 и может быть сохранен и выпустил использование dispatch_retain и dispatch_release функции. Когда подсчет ссылок очереди достигает нуля, система автоматически освобождает структуры исходных данных отгрузки.

Из-за пути они используются, владением источников отгрузки можно управлять или внутренне или внешне к самому источнику отгрузки. С внешним владением, другим объектом или частью кода берет владение источника отгрузки и ответственен за выпуск его, когда это больше не необходимо. С внутренним владением источник отгрузки владеет собой и ответственен за выпуск себя в подходящее время. Несмотря на то, что внешнее владение очень распространено, Вы могли бы использовать внутреннее владение в случаях, где Вы хотите создать автономный источник отгрузки и позволить ему управлять некоторым поведением Вашего кода без дальнейших взаимодействий. Например, если источник отгрузки разработан для ответа на единственное глобальное событие, у Вас мог бы быть он, обрабатывают то событие и затем сразу выходят.

Исходные примеры отгрузки

Следующие разделы показывают Вам, как создать и сконфигурировать некоторые более обычно используемые источники отгрузки. Для получения дополнительной информации о конфигурировании определенных типов источников отгрузки, посмотрите Ссылку Grand Central Dispatch (GCD).

Создание таймера

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

Все источники отгрузки таймера являются таймерами интервала — т.е. когда-то создаваемый, они поставляют регулярные события в интервале, который Вы указываете. При создании источника отгрузки таймера одно из значений, которые необходимо указать, является значением запаса времени для давания системе некоторое представление о желаемой точности для событий таймера. Значения запаса времени дают системе некоторую гибкость в том, как это управляет питанием и будит ядра. Например, система могла бы использовать значение запаса времени, чтобы усовершенствовать или задержать время огня и выровнять его лучше с другими системными событиями. Необходимо поэтому указать значение запаса времени, когда это возможно, для собственных таймеров.

Когда компьютер засыпает, все источники отгрузки таймера приостановлены. Когда компьютер просыпается, те источники отгрузки таймера автоматически разбужены также. Когда Ваш таймер стреляет затем, В зависимости от конфигурации таймера паузы этой природы могут влиять. Если Вы устанавливаете свой источник отгрузки таймера с помощью dispatch_time функционируйте или DISPATCH_TIME_NOW постоянный, источник отгрузки таймера использует системные часы по умолчанию для определения, когда стрелять. В то время как компьютер спит, Однако часы по умолчанию не совершенствуются. В отличие от этого, когда Вы устанавливаете свой источник отгрузки таймера с помощью dispatch_walltime функция, исходные дорожки отгрузки таймера его время увольнения к стене показывают время. Эта последняя опция является обычно подходящей для таймеров, увольнение которых интервала является относительно большим, потому что это предотвращает там от того, чтобы быть слишком большим количеством смещения между временами события.

Перечисление 4-1 показывает пример таймера, стреляющего один раз в 30 секунд и имеющего значение запаса времени 1 секунды. Поскольку интервал таймера является относительно большим, источник отгрузки создается с помощью dispatch_walltime функция. Первое увольнение таймера сразу происходит, и последующие события поступают каждые 30 секунд. MyPeriodicTask и MyStoreTimer символы представляют пользовательские функции, которые Вы записали бы, чтобы реализовать поведение таймера и сохранить таймер где-нибудь в структурах данных Вашего приложения.

Перечисление 4-1  , Создающее таймер, диспетчеризирует источник

dispatch_source_t CreateDispatchTimer(uint64_t interval,
              uint64_t leeway,
              dispatch_queue_t queue,
              dispatch_block_t block)
{
   dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
                                                     0, 0, queue);
   if (timer)
   {
      dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
      dispatch_source_set_event_handler(timer, block);
      dispatch_resume(timer);
   }
   return timer;
}
 
void MyCreateTimer()
{
   dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC,
                               1ull * NSEC_PER_SEC,
                               dispatch_get_main_queue(),
                               ^{ MyPeriodicTask(); });
 
   // Store it somewhere for later use.
    if (aTimer)
    {
        MyStoreTimer(aTimer);
    }
}
 

Несмотря на то, что создание источника отгрузки таймера является основным способом получить основанные на времени события, существуют другие опции, доступные также. Если Вы хотите выполнить блок один раз после интервала требуемого времени, можно использовать dispatch_after или dispatch_after_f функция. Эта функция ведет себя во многом как dispatch_async функционируйте за исключением того, что это позволяет Вам указывать временную стоимость, в которой можно представить блок очереди. Временная стоимость может быть указана как относительная или абсолютная временная стоимость в зависимости от Ваших потребностей.

Чтение данных из дескриптора

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

Считывая данные, необходимо всегда конфигурировать дескриптор для использования операций неблокирования. Несмотря на то, что можно использовать dispatch_source_get_data функция для наблюдения, сколько данных доступно для чтения, число, возвращенное той функцией, могла измениться между временем, Вы выполняете вызов и время, Вы фактически считываете данные. Если базовый файл является усеченным, или сетевая ошибка происходит, читая из дескриптора, блокирующего текущий поток, мог остановить Ваш обработчик событий в середине выполнения и препятствовать тому, чтобы очередь отгрузки диспетчеризировала другие задачи. Для последовательной очереди это могло завести в тупик Вашу очередь, и даже для параллельной очереди это сокращает количество новых задач, которые могут быть запущены.

Перечисление 4-2 показывает пример, конфигурирующий источник отгрузки для чтения данных из файла. В этом примере обработчик событий читает все содержание указанного файла в буфер и вызывает пользовательскую функцию (что Вы определили бы в своем собственном коде) обрабатывать данные. (Вызывающая сторона этой функции использовала бы возвращенный источник отгрузки для отмены его, как только была завершена операция чтения.), Чтобы гарантировать, что очередь отгрузки не блокирует излишне, когда нет никаких данных для чтения, этот пример использует fcntl функция для конфигурирования дескриптора файла для выполнения операций неблокирования. Обработчик отмены, установленный на источнике отгрузки, гарантирует, что дескриптор файла закрывается после того, как данные считаны.

Перечисление 4-2  , Считывающее данные из файла

dispatch_source_t ProcessContentsOfFile(const char* filename)
{
   // Prepare the file for reading.
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
      return NULL;
   fcntl(fd, F_SETFL, O_NONBLOCK);  // Avoid blocking the read operation
 
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
                                   fd, 0, queue);
   if (!readSource)
   {
      close(fd);
      return NULL;
   }
 
   // Install the event handler
   dispatch_source_set_event_handler(readSource, ^{
      size_t estimated = dispatch_source_get_data(readSource) + 1;
      // Read the data into a text buffer.
      char* buffer = (char*)malloc(estimated);
      if (buffer)
      {
         ssize_t actual = read(fd, buffer, (estimated));
         Boolean done = MyProcessFileData(buffer, actual);  // Process the data.
 
         // Release the buffer when done.
         free(buffer);
 
         // If there is no more data, cancel the source.
         if (done)
            dispatch_source_cancel(readSource);
      }
    });
 
   // Install the cancellation handler
   dispatch_source_set_cancel_handler(readSource, ^{close(fd);});
 
   // Start reading the file.
   dispatch_resume(readSource);
   return readSource;
}

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

Запись данных к дескриптору

Процесс для записи данных к файлу или сокету очень подобен процессу для чтения данных. После конфигурирования дескриптора для операций записи Вы создаете источник отгрузки типа DISPATCH_SOURCE_TYPE_WRITE. Как только тот источник отгрузки создается, системные вызовы Ваш обработчик событий, чтобы дать ему шанс начать писать данные в файл или сокет. Когда Вы закончите, пишущий данные, используйте dispatch_source_cancel функционируйте для отмены источника отгрузки.

При записи данных необходимо всегда конфигурировать дескриптор файла для использования операций неблокирования. Несмотря на то, что можно использовать dispatch_source_get_data функция для наблюдения, сколько пространства доступно для записи, значение, возвращенное той функцией, является консультацией только и могла измениться между временем, Вы выполняете вызов и время, которое Вы фактически пишете данным. Если ошибка происходит, пишущий, что данные к дескриптору файла блокирования могли бы остановить Ваш обработчик событий в середине выполнения и препятствовать тому, чтобы очередь отгрузки диспетчеризировала другие задачи. Для последовательной очереди это могло завести в тупик Вашу очередь, и даже для параллельной очереди это сокращает количество новых задач, которые могут быть запущены.

Перечисление 4-3 показывает основной подход для записи данных к файлу с помощью источника отгрузки. После создания нового файла эта функция передает получающийся дескриптор файла своему обработчику событий. Данные, помещаемые в файл, предоставлены MyGetData функция, которую Вы заменили бы любым кодом, необходимо было генерировать данные для файла. После записи данных к файлу обработчик событий отменяет источник отгрузки, чтобы препятствовать тому, чтобы он был вызван снова. Владелец источника отгрузки тогда был бы ответственен за выпуск его.

Перечисление 4-3  Пишущий данные в файл

dispatch_source_t WriteDataToFile(const char* filename)
{
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
                      (S_IRUSR | S_IWUSR | S_ISUID | S_ISGID));
    if (fd == -1)
        return NULL;
    fcntl(fd, F_SETFL); // Block during the write.
 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
                            fd, 0, queue);
    if (!writeSource)
    {
        close(fd);
        return NULL;
    }
 
    dispatch_source_set_event_handler(writeSource, ^{
        size_t bufferSize = MyGetDataSize();
        void* buffer = malloc(bufferSize);
 
        size_t actual = MyGetData(buffer, bufferSize);
        write(fd, buffer, actual);
 
        free(buffer);
 
        // Cancel and release the dispatch source when done.
        dispatch_source_cancel(writeSource);
    });
 
    dispatch_source_set_cancel_handler(writeSource, ^{close(fd);});
    dispatch_resume(writeSource);
    return (writeSource);
}

Контроль объекта файловой системы

Если Вы хотите контролировать объект файловой системы для изменений, можно установить источник отгрузки типа DISPATCH_SOURCE_TYPE_VNODE. Когда файл удален, записан в или переименован, можно использовать этот тип источника отгрузки для получения уведомлений. Когда определенные типы метаинформации для файла (такие как его размер и число каналов) изменяются, можно также использовать его, чтобы быть предупрежденными.

Перечисление 4-4 показывает пример, контролирующий файл для смен имени и выполняющий некоторое пользовательское поведение, когда это делает. (Вы обеспечили бы фактическое поведение вместо MyUpdateFileName функция вызвана в примере.), Поскольку дескриптор открыт в частности для источника отгрузки, источник отгрузки включает обработчик отмены, закрывающий дескриптор. Поскольку дескриптор файла, создаваемый примером, связан с базовым объектом файловой системы, этот тот же источник отгрузки может использоваться для обнаружения любого числа изменений имени файла.

Перечисление 4-4  , Наблюдающее за изменениями имени файла

dispatch_source_t MonitorNameChangesToFile(const char* filename)
{
   int fd = open(filename, O_EVTONLY);
   if (fd == -1)
      return NULL;
 
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,
                fd, DISPATCH_VNODE_RENAME, queue);
   if (source)
   {
      // Copy the filename for later use.
      int length = strlen(filename);
      char* newString = (char*)malloc(length + 1);
      newString = strcpy(newString, filename);
      dispatch_set_context(source, newString);
 
      // Install the event handler to process the name change
      dispatch_source_set_event_handler(source, ^{
            const char*  oldFilename = (char*)dispatch_get_context(source);
            MyUpdateFileName(oldFilename, fd);
      });
 
      // Install a cancellation handler to free the descriptor
      // and the stored string.
      dispatch_source_set_cancel_handler(source, ^{
          char* fileStr = (char*)dispatch_get_context(source);
          free(fileStr);
          close(fd);
      });
 
      // Start processing events.
      dispatch_resume(source);
   }
   else
      close(fd);
 
   return source;
}

Сигналы мониторинга

Сигналы UNIX позволяют манипулирование приложением от за пределами его домена. Приложение может получить много различных типов сигналов в пределах от неисправимых ошибок (таких как запрещенные команды) к уведомлениям о важной информации (такой как тогда, когда дочерний процесс выходит). Традиционно, приложения используют sigaction функционируйте для установки сигнальной функции-обработчика, обрабатывающей сигналы синхронно, как только они поступают. Если Вы просто хотите быть уведомленными относительно поступления сигнала и фактически не хотите обрабатывать сигнал, можно использовать сигнальный источник отгрузки для обработки сигналов асинхронно.

Сигнальные источники отгрузки не являются заменой для обработчиков сигнала синхронизации, Вы устанавливаете использование sigaction функция. Обработчики сигнала синхронизации могут фактически поймать сигнал и препятствовать тому, чтобы он завершил Ваше приложение. Сигнальные источники отгрузки позволяют Вам контролировать только поступление сигнала. Кроме того, Вы не можете использовать сигнальные источники отгрузки для получения всех типов сигналов. В частности Вы не можете использовать их для контроля SIGILL, SIGBUS, и SIGSEGV сигналы.

Поскольку сигнальные источники отгрузки выполняются асинхронно на очереди отгрузки, они не страдают от некоторых из тех же ограничений как обработчики сигнала синхронизации. Например, нет никаких ограничений на функции, которые можно вызвать от сигнального обработчика событий источника отгрузки. Компромисс для этой увеличенной гибкости является фактом, что может быть некоторая увеличенная задержка между временем, сигнал поступает и время, Ваш обработчик событий источника отгрузки вызывают.

Перечисление 4-5 показывает, как Вы конфигурируете сигнальный источник отгрузки для обработки SIGHUP сигнал. Обработчик событий для источника отгрузки вызывает MyProcessSIGHUP функция, которую Вы заменили бы в своем приложении кодом для обработки сигнала.

Перечисление 4-5  , Устанавливающее блок для контроля сигналы

void InstallSignalHandler()
{
   // Make sure the signal does not terminate the application.
   signal(SIGHUP, SIG_IGN);
 
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);
 
   if (source)
   {
      dispatch_source_set_event_handler(source, ^{
         MyProcessSIGHUP();
      });
 
      // Start processing signals
      dispatch_resume(source);
   }
}

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

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

Контроль процесса

Источник отгрузки процесса позволяет Вам контролировать поведение определенного процесса и ответить соответственно. Родительский процесс мог бы использовать этот тип источника отгрузки для контроля любых дочерних процессов, которые это создает. Например, родительский процесс мог использовать его для наблюдения за смертью дочернего процесса. Если родительский процесс выходит, точно так же дочерний процесс мог использовать его для контроля его родительского процесса и выхода.

Перечисление 4-6 показывает шаги для установки источника отгрузки для контроля для завершения родительского процесса. Когда родительский процесс умирает, источник отгрузки устанавливает некоторую информацию о внутреннем состоянии, чтобы позволить дочернему процессу знать, что это должно выйти. (Ваше собственное приложение должно было бы реализовать MySetAppExitFlag функционируйте для установки надлежащего флага для завершения.), Поскольку источник отгрузки работает автономно, и поэтому владеет собой, он также отменяет и выпускает себя в ожидании закрывающейся программы.

Перечисление 4-6  , Контролирующее смерть родительского процесса

void MonitorParentProcess()
{
   pid_t parentPID = getppid();
 
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC,
                                                      parentPID, DISPATCH_PROC_EXIT, queue);
   if (source)
   {
      dispatch_source_set_event_handler(source, ^{
         MySetAppExitFlag();
         dispatch_source_cancel(source);
         dispatch_release(source);
      });
      dispatch_resume(source);
   }
}

Отмена источника отгрузки

Источники отгрузки остаются активными, пока Вы не отменяете их явно использование dispatch_source_cancel функция. Отмена источника отгрузки останавливает поставку новых событий и не может быть отменена. Поэтому Вы обычно отменяете источник отгрузки и затем сразу выпускаете его, как показано здесь:

void RemoveDispatchSource(dispatch_source_t mySource)
{
   dispatch_source_cancel(mySource);
   dispatch_release(mySource);
}

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

Обработчик отмены является Вашим шансом освободить память или очистить любые ресурсы, полученные от имени источника отгрузки. Если Ваш источник отгрузки использует дескриптор или порт Маха, необходимо обеспечить обработчик отмены, чтобы закрыть дескриптор или уничтожить порт, когда происходит отмена. Другие типы источников отгрузки не требуют обработчиков отмены, несмотря на то, что все еще необходимо обеспечить тот при соединении какой-либо памяти или данных с источником отгрузки. Например, если Вы храните данные в указателе контекста источника отгрузки, необходимо обеспечить тот. Для получения дополнительной информации об обработчиках отмены, посмотрите Установку Обработчика Отмены.

Приостановка и возобновление источников отгрузки

Можно приостановить и возобновить поставку исходных событий отгрузки временно с помощью dispatch_suspend и dispatch_resume методы. Эти методы постепенно увеличивают и постепенно уменьшают приостановить счет для Вашего объекта отгрузки. В результате необходимо сбалансировать каждый вызов к dispatch_suspend с соответствующим вызовом к dispatch_resume перед резюме поставки события.

При приостановке источника отгрузки любые события, происходящие, в то время как тот источник отгрузки приостановлен, накапливаются, пока не возобновляется очередь. Когда очередь возобновляется, вместо того, чтобы поставить все события, события объединяются в единственное событие перед поставкой. Например, при контроле файла для смен имени поставленное событие включало бы только изменение фамилии. Объединение событий таким образом препятствует тому, чтобы они росли в очереди и подавляющий Ваше приложение, когда возобновляется работа.