From 55dcd9cc5aebbf8b9255c01e44e6cb5d36e59e81 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 26 Jan 2023 00:16:32 +0800 Subject: [PATCH 1/3] refactor(CAPI): :lock: fix busy waiting --- CAPI/API/include/Communication.h | 5 +- CAPI/API/include/logic.h | 2 + CAPI/API/src/Communication.cpp | 14 ++++- CAPI/API/src/logic.cpp | 105 ++++++++++++++++--------------- 4 files changed, 71 insertions(+), 55 deletions(-) diff --git a/CAPI/API/include/Communication.h b/CAPI/API/include/Communication.h index b1e678a..34682b8 100644 --- a/CAPI/API/include/Communication.h +++ b/CAPI/API/include/Communication.h @@ -10,6 +10,7 @@ #include "structures.h" #include #include +#include #include #include "ConcurrentQueue.hpp" @@ -18,7 +19,7 @@ class Logic; class Communication { public: - Communication(std::string sIP, std::string sPort); + Communication(std::string sIP, std::string sPort, std::mutex& mtx, std::condition_variable& cv); ~Communication() { } @@ -54,6 +55,8 @@ private: bool haveNewMessage = false; protobuf::MessageToClient message2Client; ConcurrentQueue> messageQueue; + std::mutex& mtxMessage; + std::condition_variable& cvMessage; }; #endif diff --git a/CAPI/API/include/logic.h b/CAPI/API/include/logic.h index dfc80dc..f578489 100644 --- a/CAPI/API/include/logic.h +++ b/CAPI/API/include/logic.h @@ -58,9 +58,11 @@ private: mutable std::mutex mtxAI; mutable std::mutex mtxState; mutable std::mutex mtxBuffer; + mutable std::mutex mtxMessage; std::condition_variable cvBuffer; std::condition_variable cvAI; + std::condition_variable cvMessage; // 信息队列 std::queue> messageQueue; diff --git a/CAPI/API/src/Communication.cpp b/CAPI/API/src/Communication.cpp index e189409..a43b48e 100644 --- a/CAPI/API/src/Communication.cpp +++ b/CAPI/API/src/Communication.cpp @@ -2,10 +2,14 @@ #include "utils.hpp" #include "structures.h" #include +#include +#include using grpc::ClientContext; -Communication::Communication(std::string sIP, std::string sPort) +Communication::Communication(std::string sIP, std::string sPort, std::mutex& mtx, std::condition_variable& cv) : + mtxMessage(mtx), + cvMessage(cv) { std::string aim = sIP + ':' + sPort; auto channel = grpc::CreateChannel(aim, grpc::InsecureChannelCredentials()); @@ -242,7 +246,13 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T auto MessageReader = THUAI6Stub->AddPlayer(&context, playerMsg); while (MessageReader->Read(&message2Client)) - haveNewMessage = true; + { + { + std::lock_guard lock(mtxMessage); + haveNewMessage = true; + } + cvMessage.notify_one(); + } }; std::thread(tMessage).detach(); } diff --git a/CAPI/API/src/logic.cpp b/CAPI/API/src/logic.cpp index 3ce9a3a..fcaf85f 100644 --- a/CAPI/API/src/logic.cpp +++ b/CAPI/API/src/logic.cpp @@ -187,56 +187,58 @@ void Logic::ProcessMessage() pComm->ReadMessage(playerID); while (gameState != THUAI6::GameState::GameEnd) { - if (pComm->HaveMessage2Client()) { - logger->debug("Get message from server!"); - auto clientMsg = pComm->GetMessage2Client(); - gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()]; - switch (gameState) - { - case THUAI6::GameState::GameStart: - logger->info("Game Start!"); - - // 重新读取玩家的guid,guid确保人类在前屠夫在后 - playerGUIDs.clear(); - for (auto human : clientMsg.human_message()) - playerGUIDs.push_back(human.guid()); - for (auto butcher : clientMsg.butcher_message()) - playerGUIDs.push_back(butcher.guid()); - currentState->guids = playerGUIDs; - bufferState->guids = playerGUIDs; - - LoadBuffer(clientMsg); - - AILoop = true; - UnBlockAI(); - - break; - case THUAI6::GameState::GameRunning: - // 重新读取玩家的guid,guid确保人类在前屠夫在后 - playerGUIDs.clear(); - for (auto human : clientMsg.human_message()) - playerGUIDs.push_back(human.guid()); - for (auto butcher : clientMsg.butcher_message()) - playerGUIDs.push_back(butcher.guid()); - currentState->guids = playerGUIDs; - bufferState->guids = playerGUIDs; - - LoadBuffer(clientMsg); - break; - case THUAI6::GameState::GameEnd: - AILoop = false; - { - std::lock_guard lock(mtxBuffer); - bufferUpdated = true; - counterBuffer = -1; - } - cvBuffer.notify_one(); - logger->info("Game End!"); - break; - default: - logger->debug("Unknown GameState!"); - } + std::unique_lock lock(mtxMessage); + cvMessage.wait(lock, [this]() + { return pComm->HaveMessage2Client(); }); + } + logger->debug("Get message from server!"); + auto clientMsg = pComm->GetMessage2Client(); + gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()]; + switch (gameState) + { + case THUAI6::GameState::GameStart: + logger->info("Game Start!"); + + // 重新读取玩家的guid,guid确保人类在前屠夫在后 + playerGUIDs.clear(); + for (auto human : clientMsg.human_message()) + playerGUIDs.push_back(human.guid()); + for (auto butcher : clientMsg.butcher_message()) + playerGUIDs.push_back(butcher.guid()); + currentState->guids = playerGUIDs; + bufferState->guids = playerGUIDs; + + LoadBuffer(clientMsg); + + AILoop = true; + UnBlockAI(); + + break; + case THUAI6::GameState::GameRunning: + // 重新读取玩家的guid,guid确保人类在前屠夫在后 + playerGUIDs.clear(); + for (auto human : clientMsg.human_message()) + playerGUIDs.push_back(human.guid()); + for (auto butcher : clientMsg.butcher_message()) + playerGUIDs.push_back(butcher.guid()); + currentState->guids = playerGUIDs; + bufferState->guids = playerGUIDs; + + LoadBuffer(clientMsg); + break; + case THUAI6::GameState::GameEnd: + AILoop = false; + { + std::lock_guard lock(mtxBuffer); + bufferUpdated = true; + counterBuffer = -1; + } + cvBuffer.notify_one(); + logger->info("Game End!"); + break; + default: + logger->debug("Unknown GameState!"); } } }; @@ -428,8 +430,7 @@ const std::vector Logic::GetPlayerGUIDs() const bool Logic::TryConnection() { logger->info("Try to connect to server..."); - bool result = pComm->TryConnection(playerID); - return result; + return pComm->TryConnection(playerID); } void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool file, bool print, bool warnOnly) @@ -461,7 +462,7 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool f logger->info("****************************"); // 建立与服务器之间通信的组件 - pComm = std::make_unique(IP, port); + pComm = std::make_unique(IP, port, mtxMessage, cvMessage); // 构造timer if (playerType == THUAI6::PlayerType::HumanPlayer) From 929ac31e584ca0d2cf29b572f7be40f5bd343225 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 26 Jan 2023 15:34:22 +0800 Subject: [PATCH 2/3] fix(CAPI): :bug: fix wrong consumer design --- CAPI/API/include/Communication.h | 10 +++++----- CAPI/API/include/logic.h | 2 -- CAPI/API/src/Communication.cpp | 12 ++++-------- CAPI/API/src/logic.cpp | 28 +++++++++++----------------- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/CAPI/API/include/Communication.h b/CAPI/API/include/Communication.h index 34682b8..bcc639b 100644 --- a/CAPI/API/include/Communication.h +++ b/CAPI/API/include/Communication.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "ConcurrentQueue.hpp" class Logic; @@ -19,7 +20,7 @@ class Logic; class Communication { public: - Communication(std::string sIP, std::string sPort, std::mutex& mtx, std::condition_variable& cv); + Communication(std::string sIP, std::string sPort); ~Communication() { } @@ -45,18 +46,17 @@ public: bool TryConnection(int64_t playerID); protobuf::MessageToClient GetMessage2Client(); - bool HaveMessage2Client(); void AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, THUAI6::HumanType humanType, THUAI6::ButcherType butcherType); void ReadMessage(int64_t playerID); private: std::unique_ptr THUAI6Stub; - bool haveNewMessage = false; + std::atomic_bool haveNewMessage = false; protobuf::MessageToClient message2Client; ConcurrentQueue> messageQueue; - std::mutex& mtxMessage; - std::condition_variable& cvMessage; + std::mutex mtxMessage; + std::condition_variable cvMessage; }; #endif diff --git a/CAPI/API/include/logic.h b/CAPI/API/include/logic.h index f578489..dfc80dc 100644 --- a/CAPI/API/include/logic.h +++ b/CAPI/API/include/logic.h @@ -58,11 +58,9 @@ private: mutable std::mutex mtxAI; mutable std::mutex mtxState; mutable std::mutex mtxBuffer; - mutable std::mutex mtxMessage; std::condition_variable cvBuffer; std::condition_variable cvAI; - std::condition_variable cvMessage; // 信息队列 std::queue> messageQueue; diff --git a/CAPI/API/src/Communication.cpp b/CAPI/API/src/Communication.cpp index a43b48e..f8962e8 100644 --- a/CAPI/API/src/Communication.cpp +++ b/CAPI/API/src/Communication.cpp @@ -7,9 +7,7 @@ using grpc::ClientContext; -Communication::Communication(std::string sIP, std::string sPort, std::mutex& mtx, std::condition_variable& cv) : - mtxMessage(mtx), - cvMessage(cv) +Communication::Communication(std::string sIP, std::string sPort) { std::string aim = sIP + ':' + sPort; auto channel = grpc::CreateChannel(aim, grpc::InsecureChannelCredentials()); @@ -202,15 +200,13 @@ bool Communication::TryConnection(int64_t playerID) protobuf::MessageToClient Communication::GetMessage2Client() { + std::unique_lock lock(mtxMessage); + cvMessage.wait(lock, [this]() + { return haveNewMessage.load(); }); haveNewMessage = false; return message2Client; } -bool Communication::HaveMessage2Client() -{ - return haveNewMessage; -} - std::optional> Communication::GetMessage() { return messageQueue.tryPop(); diff --git a/CAPI/API/src/logic.cpp b/CAPI/API/src/logic.cpp index fcaf85f..9046c6d 100644 --- a/CAPI/API/src/logic.cpp +++ b/CAPI/API/src/logic.cpp @@ -187,13 +187,8 @@ void Logic::ProcessMessage() pComm->ReadMessage(playerID); while (gameState != THUAI6::GameState::GameEnd) { - { - std::unique_lock lock(mtxMessage); - cvMessage.wait(lock, [this]() - { return pComm->HaveMessage2Client(); }); - } + auto clientMsg = pComm->GetMessage2Client(); // 在获得新消息之前阻塞 logger->debug("Get message from server!"); - auto clientMsg = pComm->GetMessage2Client(); gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()]; switch (gameState) { @@ -227,20 +222,19 @@ void Logic::ProcessMessage() LoadBuffer(clientMsg); break; - case THUAI6::GameState::GameEnd: - AILoop = false; - { - std::lock_guard lock(mtxBuffer); - bufferUpdated = true; - counterBuffer = -1; - } - cvBuffer.notify_one(); - logger->info("Game End!"); - break; default: logger->debug("Unknown GameState!"); + break; } } + AILoop = false; + { + std::lock_guard lock(mtxBuffer); + bufferUpdated = true; + counterBuffer = -1; + } + cvBuffer.notify_one(); + logger->info("Game End!"); }; std::thread(messageThread).detach(); } @@ -462,7 +456,7 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool f logger->info("****************************"); // 建立与服务器之间通信的组件 - pComm = std::make_unique(IP, port, mtxMessage, cvMessage); + pComm = std::make_unique(IP, port); // 构造timer if (playerType == THUAI6::PlayerType::HumanPlayer) From 34feec7c99356b1a6891cc7770e3ab08f95152c0 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 26 Jan 2023 16:46:27 +0800 Subject: [PATCH 3/3] perf(CAPI): :zap: remove unnecessary atomic --- CAPI/API/include/Communication.h | 2 +- CAPI/API/src/Communication.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CAPI/API/include/Communication.h b/CAPI/API/include/Communication.h index bcc639b..dbcdf2e 100644 --- a/CAPI/API/include/Communication.h +++ b/CAPI/API/include/Communication.h @@ -52,7 +52,7 @@ public: private: std::unique_ptr THUAI6Stub; - std::atomic_bool haveNewMessage = false; + bool haveNewMessage = false; protobuf::MessageToClient message2Client; ConcurrentQueue> messageQueue; std::mutex mtxMessage; diff --git a/CAPI/API/src/Communication.cpp b/CAPI/API/src/Communication.cpp index f8962e8..78d659f 100644 --- a/CAPI/API/src/Communication.cpp +++ b/CAPI/API/src/Communication.cpp @@ -202,7 +202,7 @@ protobuf::MessageToClient Communication::GetMessage2Client() { std::unique_lock lock(mtxMessage); cvMessage.wait(lock, [this]() - { return haveNewMessage.load(); }); + { return haveNewMessage; }); haveNewMessage = false; return message2Client; }