Created
November 15, 2015 08:57
-
-
Save hamsham/b5853bb10ffd046d5ee0 to your computer and use it in GitHub Desktop.
Example of loading files on a separate thread in C++11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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