packaged_task
bir callable objeyi paketleyip sonucunu daha sonra kulanabiliriz. Senkron ya da asekron olarak çalışabilir. Eğer aynı thread de ise sekron olarak çalışır:
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int delta(int a, int b) {
cout << "Delta is run" << endl;
this_thread::sleep_for(chrono::seconds(2)); // Simulate a delay
return max(a - b, b - a);
}
int main() {
packaged_task<int(int, int)> task(delta);
future<int> result = task.get_future();
cout << "A" << endl;
task(44, 25); // Call the task with arguments 10 and 5
cout << "B" << endl;
cout << "Delta: " << result.get() << endl; // Retrieve the result from the future
cout << "C" << endl;
}
// A
// Delta is run
// B
// Delta : 19
// CFarklı thread’de asekron olarak da çalıştırabiliriz:
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int delta(int a, int b) {
cout << "Delta is run" << endl;
this_thread::sleep_for(chrono::seconds(2)); // Simulate a delay
return max(a - b, b - a);
}
int main() {
packaged_task<int(int, int)> task(delta);
future<int> result = task.get_future();
cout << "A" << endl;
thread t(move(task), 44, 25); // Start the task in a separate thread
//task(44, 25); // Call the task with arguments 10 and 5
cout << "B" << endl;
cout << "Delta: " << result.get() << endl; // Retrieve the result from the future
cout << "C" << endl;
t.join(); // Wait for the thread to finish
}
// A
// B
// Delta : Delta is run
// 19
// Cpackaged_task şablonu:
// Synchronous (in current thread)
packaged_task<int(int, int)> task(delta);
future<int> result = task.get_future();
task(44, 25);
result.get();
// Asynchronous (in new thread)
packaged_task<int(int, int)> task(delta);
future<int> result = task.get_future();
thread t(move(task), 44, 25);
result.get();
t.join();Async
packaged_task ile aşağı yukarı aynı işi yapıyor ama daha high level diyebiliriz. Sekron ya da asekron çalışabilir:
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int delta(int a, int b) {
return max(a - b, b - a);
}
int main() {
auto result = async(delta, 44, 25);
cout << "Delta: " << result.get() << endl;
}
future objesi implicitly olarak thread join i çağırıyor.
Launch policies
auto result = async(launch::async, delta, 44, 25);
auto result = async(launch::deferred, delta, 44, 25);std::launch::async- Runs the function immediately in a new thread.
- Truly asynchronous.
- Useful when you want concurrency.
std::launch::deferred- The function doesn’t run until you call
get()orwait()on the future. - Runs synchronously, in the same thread that calls
get(). - lazy evaluation
- The function doesn’t run until you call
- std::launch::async | std::launch::deferred
- default option
- c++ decide which will chosen
Örnek: Dosya yükleme
Asekron dosya yükleme işlemi için notlarıma geri dönüp baktığımda kullanışlı bir kod şablonu bulamadım. Bu sebepten ufak bir karalama yapayım dedim.
- Asekron olarak dosya yüklemeyi başlat
- main thread’de çalışan main loop içerisinde asekron işin bitip bitmediğini güncelle
- Eğer iş bittiyse döngüden çık.
#include <iostream>
#include <future>
using namespace std;
// dosyanın nyüklenme durumunu ifade eden enum
enum class LoadStatus { None, Loading, ReadyToUpload, Complete, Error };
// dosyanın yüklendiği fonksiyon
LoadStatus loadResourceAsync()
{
// Heavy work
this_thread::sleep_for(chrono::seconds(5));
return LoadStatus::Complete;
}
// işin durumu hakkında bilgi veren bayraklar
future<LoadStatus> _asyncLoadStatus;
LoadStatus _loadStatus = LoadStatus::None;
LoadStatus getResourceStatus() {
return _loadStatus;
}
// dosya yüklemesini başlatan fonksiyon
void init() {
_asyncLoadStatus = async(launch::async, loadResourceAsync);
}
// dosyanın yüklemesinin bitip bitmediğini sorgular
void update() {
if (_asyncLoadStatus.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
_loadStatus = _asyncLoadStatus.get();
}
int main()
{
std::cout << "Async file loading!\n";
init(); // Task async olarak çalışmaya başlar
// MAIN PROGRAM LOOP
while (true) {
// Do some works while the file is loading
this_thread::sleep_for(chrono::seconds(1));
std::cout << "waiting...\n";
// check and update file loading status
update();
// if loading was complete:
if (getResourceStatus() == LoadStatus::Complete)
break;
}
cout << "Done" << endl;
return EXIT_SUCCESS;
}
// Programın çıktısı
//
// Async file loading!
// waiting...
// waiting...
// waiting...
// waiting...
// waiting...
// Done
C++aynı kodu daha sade bir halde yazarsak:
#include <iostream>
#include <future>
using namespace std;
enum class LoadStatus { None, Loading, ReadyToUpload, Complete, Error };
future<LoadStatus> _asyncLoadStatus;
LoadStatus _loadStatus = LoadStatus::None;
LoadStatus loadResourceAsync(){
this_thread::sleep_for(chrono::seconds(5));// Heavy work
return LoadStatus::Complete;
}
int main(){
std::cout << "Async file loading!\n";
_asyncLoadStatus = async(launch::async, loadResourceAsync);
// MAIN LOOP
while (true) {
this_thread::sleep_for(chrono::seconds(1)); // Do some work
std::cout << "waiting...\n";
auto futureStatus = _asyncLoadStatus.wait_for(std::chrono::seconds(0));
if (futureStatus == std::future_status::ready)
_loadStatus = _asyncLoadStatus.get();
if (_loadStatus == LoadStatus::Complete)
break;
}
cout << "Done" << endl;
return EXIT_SUCCESS;
}C++Elbette bu iş için daha zarif çözüm yolları olabilir fakat bu benim şimdilik uyguladığım bir yöntem.
Benim kullanacağım use case aşağı yukarı şöyle bir durum:
// C++PlayGround.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <future>
using namespace std;
enum class LoadStatus { None, Loading, ReadyToUpload, Complete, Error };
class dummyFile {
private:
future<LoadStatus> _asyncLoadStatus;
LoadStatus _loadStatus = LoadStatus::None;
string isim{};
LoadStatus loadResourceAsync() {
this_thread::sleep_for(chrono::seconds(5));// Heavy work
return LoadStatus::Complete;
}
public:
void init(string isim){
this->isim = isim;
cout << "File loading: " << isim << endl;
// async teki this 'e dikkat et!
_asyncLoadStatus = async(launch::async, &dummyFile::loadResourceAsync, this);
}
void update() {
if (_asyncLoadStatus.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
cout << "File was loaded: " << isim << endl;
_loadStatus = _asyncLoadStatus.get();
}
}
LoadStatus getResourceStatus() { return _loadStatus; }
};
int main(){
std::cout << "Async file loading!\n";
vector<dummyFile> dummy(5);
dummy[0].init("d0");
dummy[1].init("d1");
this_thread::sleep_for(chrono::seconds(1));
dummy[2].init("d2");
dummy[3].init("d3");
dummy[4].init("d4");
int loadingFileCount = 0;
loadingFileCount = dummy.size();
// MAIN LOOP
while (true) {
this_thread::sleep_for(chrono::seconds(1)); // Do some work
std::cout << "waiting...\n";
bool isAllFilesLoaded = true;
// File loading check loop
for (dummyFile& d : dummy) {
if (d.getResourceStatus() != LoadStatus::Complete) {
d.update(); // sadece bitmemiş dosyaları update ediyoruz. Yoksa hata alırız.
isAllFilesLoaded = false;
}
}
if (isAllFilesLoaded)
break;
}
cout << "All files loaded successfully " << endl;
return EXIT_SUCCESS;
}
// Async file loading!
// File loading : d0
// File loading : d1
// File loading : d2
// File loading : d3
// File loading : d4
// waiting...
// waiting...
// waiting...
// waiting...
// File was loaded : d0
// File was loaded : d1
// waiting...
// File was loaded : d2
// waiting...
// File was loaded : d3
// File was loaded : d4
// waiting...
// All files loaded successfullyC++
Leave a Reply