From e6d882f34309c8aca36f4d5c36a8b2eacdc033af Mon Sep 17 00:00:00 2001 From: Mahdijamebozorg Date: Sun, 12 Feb 2023 00:49:59 +0330 Subject: [PATCH] Threads exception handling added --- .vscode/settings.json | 3 ++- include/GameManager.hpp | 9 +++++--- src/Filemanager.cpp | 20 ++++++++++------- src/GameManager.cpp | 49 ++++++++++++++++++++++++----------------- 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 073fee5..cd1cb4a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,6 +53,7 @@ "stop_token": "cpp", "streambuf": "cpp", "thread": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "stack": "cpp" } } \ No newline at end of file diff --git a/include/GameManager.hpp b/include/GameManager.hpp index 3994f87..6c8fd2d 100644 --- a/include/GameManager.hpp +++ b/include/GameManager.hpp @@ -50,9 +50,6 @@ class GameManager //-------------------------------------------- File - // keeps file operation thread - std::thread fileOperation; - FileManager *getFileManager(bool endPreviewsOp = true); // gets a callable and replace it to fileOp thread @@ -180,6 +177,12 @@ class GameManager Enpasan enpasan = std::make_pair(100, 100); FileManager fileManager; + + // keeps file operation thread + std::thread fileOperation; + + // store threads exceptions + std::exception_ptr globalExpPtr = nullptr; }; #endif /* end of include guard: GAMEMANAGER_H*/ diff --git a/src/Filemanager.cpp b/src/Filemanager.cpp index 4d9b49d..0598e46 100644 --- a/src/Filemanager.cpp +++ b/src/Filemanager.cpp @@ -11,7 +11,7 @@ using namespace std; //------------------------------------------------------------------------- reading game from file void FileManager::readFile(std::string fileName, bool isChecking) { - // reset remove files details + // remove previews files details resetData(); // dir @@ -39,11 +39,16 @@ void FileManager::readFile(std::string fileName, bool isChecking) getline(file, p1_Name); getline(file, p2_Name); + qDebug() << "user1:" << QString::fromStdString(p1_Name) << "\tuser2" << QString::fromStdString(p2_Name); + // if players names are empty - if (!isChecking && (p1_Name.empty() || p2_Name.empty())) + if (p1_Name.empty() || p2_Name.empty()) { file.close(); - throw LoadingFailed("Users names have not been saved well in file " + file_Dir); + if (isChecking) + throw CheckingFailed("Users names have not been saved well in file: " + file_Dir); + else + throw LoadingFailed("Users names have not been saved well in file: " + file_Dir); } // read moves in file @@ -76,7 +81,7 @@ void FileManager::readFile(std::string fileName, bool isChecking) // if has unknow moves if (!isPrm && (tempMove.size() < 18 || tempMove.size() > 28)) { - resetData(); + file.close(); // if is checking the file if (isChecking) { @@ -279,29 +284,27 @@ void FileManager::set_newFile(std::string gameName) set_Name(gameName); this->file_Dir = "./SavedGames/" + game_Name + "(AutoSave)" + ".txt"; + + file.open(file_Dir.c_str(), ios::out); if (!file.is_open() || file.bad()) { file.close(); throw(OpenFileFailed("can't open file in set game")); } - file.close(); } //------------------------------------------------------------------------------------------- void FileManager::set_P1_Name(std::string name) { - file.open(file_Dir, ios::trunc | ios::out); this->p1_Name = name; file << p1_Name << '\n'; - file.close(); } //------------------------------------------------------------------------------------------- void FileManager::set_P2_Name(std::string name) { - file.open(file_Dir, ios::ate); this->p2_Name = name; file << p2_Name << '\n'; file.close(); @@ -425,6 +428,7 @@ void FileManager::resetData() this->p2_Score = 0; this->p1_Name.clear(); this->p2_Name.clear(); + this->game_Name.clear(); this->file_Dir.clear(); this->moves.clear(); } diff --git a/src/GameManager.cpp b/src/GameManager.cpp index aecface..c649a70 100644 --- a/src/GameManager.cpp +++ b/src/GameManager.cpp @@ -56,7 +56,19 @@ void GameManager::addFileOperation(Func func) fileOperation.join(); // make a thread for function - thread th(func); + thread th([this, func]() + { + // transfer exceptions using exception pointer + globalExpPtr = nullptr; + try + { + func(); + } + catch (...) + { + globalExpPtr = current_exception(); + } // + }); // add thread to fileOperation fileOperation.swap(th); @@ -72,23 +84,22 @@ void GameManager::loadGame(unsigned index) { getFileManager(false)->loadSaveFile(index); }; addFileOperation(fileOp); + // catch fileOperation exceptions + fileOperation.join(); + if (globalExpPtr) + rethrow_exception(globalExpPtr); + this->game_name = getFileManager()->get_Game_Name(); string name1 = getFileManager()->get_P1_Name(), name2 = getFileManager()->get_P2_Name().c_str(); // *important* - // because of using static var for setting pieces names, + // because of using static var for setting pieces ids, // we can't use multithreading for setting users - // user 1 setup - users[0] = User::getInstance(name1, Chessman::Color::WHITE, 0, 0); - users[0]->setColor(Chessman::Color::WHITE); - users[0]->setChessmansIn(); // - - // user 2 setup - users[1] = User::getInstance(name2, Chessman::Color::WHITE, 0, 0); - users[1]->setColor(Chessman::Color::BLACK); - users[1]->setChessmansIn(); // + // users setup + this->users[0] = User::getInstance(name1, User::Color::WHITE, 0, 0); + this->users[1] = User::getInstance(name2, User::Color::BLACK, 0, 0); this->setTurn(Turn::USER1); @@ -723,17 +734,13 @@ void GameManager::restartGame() { getFileManager(false)->resetFile(); }; addFileOperation(fileOp1); - // reset FileManager data - auto fileOp2 = [this]() - { getFileManager(false)->resetData(); }; - addFileOperation(fileOp2); - // reset game data resetData(); - // *important* these can't be paralel - setUser1(temp_name1); - setUser2(temp_name2); + this->users[0] = User::getInstance(temp_name1, User::Color::WHITE, 0, 0); + this->users[1] = User::getInstance(temp_name2, User::Color::BLACK, 0, 0); + + setTurn(USER1); startGame(); } @@ -1251,8 +1258,10 @@ string GameManager::getSaveFileInfo(unsigned index) { data = getFileManager(false)->getSaveFileInfo(index); }; addFileOperation(fileOp); - // ensure op is done + // catch fileOperation exceptions fileOperation.join(); + if (globalExpPtr) + rethrow_exception(globalExpPtr); return data; }