I recently started work on my own Async file input "library" in C++. I got it done today and I decided to put it on Code Review to see how well I actually did, and where I can still improve the code.

The `log++` `#include` is just some logging header I created for writing colored output to the console.

EDIT: Since the time I have posted this I made some huge changes to the code, so I guess I will post an updated version of it below:

AsyncTask.h
-----------

```
#pragma once

#include <iostream>
#include <fstream>
#include <thread>
#include <string>
#include <sstream>
#include <mutex>
#include <functional>
#include <condition_variable>
#include "logpp/log++.h"

class AsyncTask
{
public:

    AsyncTask();

    template<typename Callable, typename ...Args>
    explicit AsyncTask(Callable task, Args&&... args);
    ~AsyncTask();

    /*Manually starts the task if it is not already running*/
    template<typename Callable, typename ...Args>
    void start(Callable func, Args&&... args);

    /*Interrupts the task until resume() is called*/
    void pause();

    /*Unpauses the task*/
    void resume();

    /*Blocks calling thread until the task is done*/
    void wait();

    bool is_complete();

    /*Stops the task and resets all it's data*/
    virtual void reset();

private:

    std::thread m_exec_thread;

    bool m_running;
    bool m_paused;

    std::condition_variable m_pause_cv;
    std::mutex m_pause_mutex;

protected:
    void handle_pause_update();
    void toggle_running();
};

template<typename Callable, typename... Args>
AsyncTask::AsyncTask(Callable task, Args&&... args) : m_running(false), m_paused(false)
{
    start(task, std::forward<Args>(args)...);
}

template<typename Callable, typename ...Args>
void AsyncTask::start(Callable func, Args&&... args)
{
    /*Only start the task if it is not already running*/
    if (!m_running)
    {
        m_exec_thread = std::thread(func, std::forward<Args>(args)...);
        m_running = true;
    }
}

class AsyncReadTask : public AsyncTask
{
public:
    AsyncReadTask();
    explicit AsyncReadTask(std::string const& filename);

    /*Obtain data that was read from the file. Will reset the task*/
    std::stringstream get_data();

    void start(std::string const& filename);

    virtual void reset() override;

private:
    std::stringstream m_data;
    std::string m_file;

    void read(std::string const& file_name);
};

```

AsyncTask.cpp
-------------

```
#include "AsyncTask.h"

#pragma region AsyncTaskImpl

AsyncTask::AsyncTask()
{

}

void AsyncTask::handle_pause_update()
{
    while (m_paused) //check if we have to pause
    {
        std::unique_lock<std::mutex> lk { m_pause_mutex };
        m_pause_cv.wait(lk);
        lk.unlock();
    }
}

void AsyncTask::pause()
{
    if (m_paused) //don't double pause
        return;
    std::lock_guard<std::mutex> lk { m_pause_mutex };
    m_paused = true;
}

void AsyncTask::resume()
{
    std::lock_guard<std::mutex> lk { m_pause_mutex };
    m_paused = false;
    m_pause_cv.notify_one();
}

void AsyncTask::wait()
{
    while (m_running)
    {
        //wait
    }
}

bool AsyncTask::is_complete()
{
    return !m_running;
}

void AsyncTask::reset()
{
    wait();
    m_running = false;

}

void AsyncTask::toggle_running()
{
    m_running = !m_running;
}

AsyncTask::~AsyncTask()
{
    m_exec_thread.join();
}

#pragma endregion AsyncTaskImpl

#pragma region AsyncReadTaskImpl

std::stringstream AsyncReadTask::get_data()
{
    wait();

    auto data = std::move(m_data);
    reset();
    return std::move(data);
}

void AsyncReadTask::read(std::string const& file_name)
{
    /*---Open File---*/

    std::ifstream in(file_name);

    logpp::Console::log_assert(in.good() && in.is_open(), "Could not open file: " + file_name);

    /*---Read data---*/

    std::string line;
    while (std::getline(in, line))
    {
        line += "\n"; //getline removes the newline character, but we want to give the stringstream the exact same data as the file

        m_data << line;

        handle_pause_update();
    }

    /*---Cleanup---*/

    in.close();
    toggle_running();
}

AsyncReadTask::AsyncReadTask()
{

}

AsyncReadTask::AsyncReadTask(std::string const& filename) : AsyncTask(&AsyncReadTask::read, this, filename), m_file(filename)
{

}

void AsyncReadTask::start(std::string const& file_name)
{
    AsyncTask::start(&AsyncReadTask::read, this, file_name);
}

void AsyncReadTask::reset() 
{
    AsyncTask::reset();

    m_data.clear();
    m_file = "";
}

#pragma endregion AsyncReadTaskImpl

```

The full source can be found on [GitHub](https://github.com/CodeSheep123/FileSystem/tree/master/FileSystem) too.