суббота, 5 марта 2016 г.

Указатели на функции: использование.

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

  Но как работать с асинхронными операциями? Давайте представим, что функция "downloadFile" скачивает файл из Интернета по ссылке, что приходит в эту функцию как параметр. И возвращает указатель на массив байтов, если файл успешно скачан. Раньше мы бы поступили так:


#include <iostream>

#include <stdint.h>

uint8_t* downloadFile(const char* link)

{
  // ...
  // downloading here
  // ...
  return fileData;

}

int main()
{

  if(downloadFile("http://www.???.com/picture.png") == nullptr)
  {
    std::cout << "Failed to download" << std::endl;
  }

  return 0;
}


  В зависимости от размера файла и скорости Интернет соединения, "на строке кода" с загрузкой файла можно остановится на некоторое время, пока он не скачается.


  Многопоточность предлагает нам следующий вариант: запустить загрузку файла в отдельном потоке и мгновенно продолжить выполнять код дальше.


#include <iostream>

#include <stdint.h>

uint8_t* downloadFileAsync(const char* link)

{
  // downloading here
  return fileData;
}

int main()
{

  downloadFileAsync("http://www.???.com/picture.png");
  
  std::cout << "File is not downloaded, but we are already here";
  std::cout << std::endl;
  system("pause");

  return 0;
}


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


#include <iostream>

#include <stdint.h>

void onFileDownload(uint8_t* fileData)

{
  if(fileData != nullptr)
  {
    std::cout << "File downloaded successfully";
    // performing some operations on file data
  }
  else
  {
    std::cout << "Failed to download file";
  }
}

typedef void (*downloadFileCallback_t)(uint8_t* fileData);


void downloadFileAsync

(
  const char* link,
  downloadFileCallback_t callback
)
{
  // downloading here
  callback(fileData);
}

int main()
{

  downloadFileAsync("http://www.???.com/picture.png", onFileDownload);
  
  std::cout << "File is not downloaded, but we are already here";
  std::cout << std::endl;
  system("pause");

  return 0;
}


  Я написал функцию, что должна вызваться в случае завершения загрузки файла. И передал ее в функцию загрузки файла через указатель. Теперь случится следующее: после вызова(но не после завершения!) функции downloadFileAsync я тут же окажусь на выходе из программы. Но! Когда асинхронная операция загрузки файла закончится, она вызовет мою функцию обработки загрузки этого файла: "callback(fileData);" и после этого я окажусь в функции "onFileDownload", где и продолжу работать с загруженным файлом.

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

Комментариев нет:

Отправить комментарий