Skip to content

Instantly share code, notes, and snippets.

@hamsham
Created November 15, 2015 08:57
Show Gist options
  • Save hamsham/b5853bb10ffd046d5ee0 to your computer and use it in GitHub Desktop.
Save hamsham/b5853bb10ffd046d5ee0 to your computer and use it in GitHub Desktop.
Example of loading files on a separate thread in C++11
/*
* Testing the loading of file data using a thread
* g++ -std=c++11 -Wall -Werror -Wextra -pedantic-errors -O3 -lpthread thread_load.cpp -o thread_load
*/
#include <atomic>
#include <chrono>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>
#include <vector>
/*
* Typedefs
*/
using std::chrono::duration_cast;
using std::chrono::system_clock;
typedef std::chrono::nanoseconds timespan;
typedef std::chrono::time_point<std::chrono::system_clock> time_point;
/**
* Load Class error codes
*/
enum load_status_t : int {
LOAD_STATUS_ERROR,
LOAD_STATUS_SUCCESS,
LOAD_STATUS_LOADING,
LOAD_STATUS_UNLOADED,
};
/**
* Simple typedef for a vector of bytes
*/
typedef std::vector<char> fileData;
/**
* Class to load raw file data into memory
*/
class fileLoader {
private:
/*
* Helper function to load data
*/
static void loadDataThreaded(std::string path, fileData& data, std::mutex& mtx, std::atomic_int& status) {
std::lock_guard<std::mutex> lock{mtx};
data.clear();
std::ifstream fin{path, std::ios_base::in | std::ios_base::binary};
if (!fin.good()) {
std::cerr << "ERROR: Unable to open " << path << '.' << std::endl;
status.store(LOAD_STATUS_ERROR);
return;
}
fin.seekg(0, std::ios_base::end);
const std::size_t byteCount = fin.tellg();
fin.seekg(0, std::ios_base::beg);
data.resize(byteCount);
char* const pData = &data[0];
fin.read(pData, byteCount);
fin.close();
status.store(LOAD_STATUS_SUCCESS);
}
private:
fileData loadData;
std::thread loadThread;
std::mutex loadMutex;
std::atomic_int loadStatus = {LOAD_STATUS_UNLOADED};
public:
/**
* Destructor
*/
~fileLoader() {
unload();
}
/**
* Determine if a file is currently loading
*/
bool isLoading() const {return loadStatus.load() == LOAD_STATUS_LOADING;}
/**
* Check if a file has loaded
*/
bool isLoaded() const {return loadStatus.load() == LOAD_STATUS_SUCCESS;}
/**
* Check if something went wrong when loading a file
*/
bool isLoadFailed() const {return loadStatus.load() == LOAD_STATUS_ERROR;}
/**
* Load raw file data using a separate thread
*/
void load(const std::string& filename);
/**
* Unload the data that a file had in placed in heap memory
*/
void unload() {
if (loadThread.joinable()) {
loadThread.join();
}
loadData.clear();
}
/**
* Get a reference to the data that a file had loaded into memory
*/
fileData& getData() {
if (loadThread.joinable()) {
loadThread.join();
}
return loadData;
}
};
/*
* Use a thread to load data
*/
void fileLoader::load(const std::string& filename) {
if (loadThread.joinable()) {
loadThread.join();
return;
}
loadStatus.store(LOAD_STATUS_LOADING);
loadThread = std::thread{loadDataThreaded, filename, std::ref(loadData), std::ref(loadMutex), std::ref(loadStatus)};
}
/**
* Main()
*/
int main(int argc, char** argv) {
fileData data;
fileLoader loader;
std::cout << "Sizeof data Loader: " << sizeof(fileLoader) << std::endl;
if (argc < 2) {
std::cout << "Enter the path to a valid file." << std::endl;
return -1;
}
else {
std::cout << "Loading File: " << argc << ": " << argv[1] << std::endl;
loader.load(std::string{argv[1]});
}
const time_point startTime = system_clock::now();
time_point endTime = system_clock::now();
do {
endTime = system_clock::now();
std::cout
<< std::setprecision(std::numeric_limits<float>::digits10)
<< "Time to Load: "
<< duration_cast<timespan>(endTime-startTime).count()
<< "\t\r";
}
while (loader.isLoading());
std::cout << std::endl;
data = std::move(loader.getData());
loader.unload();
std::cout
<< "File Size: "
<< std::setprecision(std::numeric_limits<float>::digits10)
<< (float)data.size()/1024.f/1024.f << "mb."
<< std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment