CPP 062 – packaged_task & async

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
// C

Farklı 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
// C

packaged_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() or wait() on the future.
    • Runs synchronously, in the same thread that calls get().
    • lazy evaluation
  • 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 successfully
C++


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *