Все приложения, что нам с Вами довелось писать - однопоточные. Иными словами, все действия в них выполняются последовательно. К примеру, пока Вы вводите значения с клавиатуры, ничего кроме ввода не происходит. А ведь в это время можно было что-то посчитать, загрузить файл из Интернета или сжать данные. Как это делается я расскажу позже. А сейчас лишь хочу сказать, что подавляющее большинство программ умеет выполнять действия параллельно, в разных потоках.
Но как работать с асинхронными операциями? Давайте представим, что функция "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", где и продолжу работать с загруженным файлом.
Не вдавайтесь сейчас в подробности многопоточности. Это был просто хороший пример использования указателей на функции. Надеюсь, хороший.
Но как работать с асинхронными операциями? Давайте представим, что функция "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", где и продолжу работать с загруженным файлом.
Не вдавайтесь сейчас в подробности многопоточности. Это был просто хороший пример использования указателей на функции. Надеюсь, хороший.
Комментариев нет:
Отправить комментарий