Цикл работает только тогда, когда есть вывод
Есть c++ приложение, построенное на SDL2 и boost. В приложении есть сервер и клиент, у сервера есть 2 метода, которые мы выполняем в отдельных потоках. Первый принимает новых клиентов, а второй итерируется по массиву клиентов и для каждого выполняет метод tick, которые передвигает игрока. Так же для каждого нового клиента у нас выделяется новый поток. Проблема заключается в цикле, который передвигает игроков. Он работает, только если в коде мы вызываем метод SDL_GetTicks() или std::cout <<, при этом от размера выведенного текста зависит производительность Код запуска сервера (сервер запускает клиент)
int StartHostGame(std::string MyIp, std::string MyPort, std::string MyName)
{
auto const ip = boost::asio::ip::make_address(MyIp);
boost::asio::ip::tcp::endpoint ep(ip, std::stoi(MyPort));
std::thread gameing(boost::bind(gm));//Итератор по всем клиентам
std::thread clients(boost::bind(NewClient, boost::cref(ep)));//Аццептор клиентов
gameing.detach();
clients.detach();
ConnectGame(ip, std::stoi(MyPort), MyName); // Клиент
return 0;
}
А вот и код метода с итерацией
void gm() {
UINT32 lastTick;
while (true) {
if (PlayersCounter > 0) {
for (auto it = Players.begin(); it < Players.end(); it++) {
if (GameTir == GameTirs::started) {
it->get()->Tick();
}
}
}
//std::cout << "";//Код работает в зависимости от этой строчки, если её нет или она закомментирована, то всё "стоит"
}
}
Код клиента:
struct Location {
private:
float PositionX = 0;
float PositionY = 0;
public:
Location() {};
float& GetX() { return PositionX; }
float& GetY() { return PositionY; }
float SetX(float NewPosition) { PositionX = NewPosition; }
float SetY(float NewPosition) { PositionY = NewPosition; }
std::pair<float, float> GetPosition() { return { PositionX,PositionY };}
void SetPosition(float x, float y) { PositionX = x; PositionY = y; }
void AddPosition(float x, float y) { PositionX += x; PositionY += y; }
};
struct Player : boost::enable_shared_from_this<Player>, Location{
private:
bool Host = false;
int MaxHp = 100;
int Hp = 100;
const int id;
int VelocityX = 0, VelocityY = 0;
float speed = 0.0001;
std::string Name;
std::string Team;
boost::asio::io_service service;
boost::asio::ip::tcp::socket PlayerSocket;
public:
boost::asio::ip::tcp::socket& GetSocket() { return PlayerSocket; }
const int& GetId() { return id; }
bool IsHost() { return Host; }
void SetHost() { Host = true; }
void SetVelocity(int X, int Y) { VelocityX = X; VelocityY = Y; }
void Tick() { AddPosition(speed*VelocityX, speed*VelocityY); }
std::string& GetName() { return Name; }
Player()
: PlayerSocket(service),
id(PlayersCounter + 1),
Location::Location() {}
};
typedef boost::shared_ptr<Player> client_ptr;
std::vector<client_ptr> Players;
Код приёма новых пользователей
void NewClient(boost::asio::ip::tcp::endpoint ep) {
while (true) {
boost::asio::ip::tcp::acceptor ServerAccpetor(service, ep);
client_ptr new_(new Player);
ServerAccpetor.accept(new_->GetSocket());
ServerAccpetor.close();
std::vector<char> buffer(new_.get()->GetSocket().available());
new_.get()->GetSocket().receive(boost::asio::buffer(buffer, sizeof(buffer)));
std::string BufferName(buffer.begin(), buffer.end());
bool rightNick = true;
for (auto it = Players.begin(); it < Players.end(); it++) { if (it->get()->GetName() == BufferName) { new_.get()->GetSocket().close(); rightNick = false; } }
if (rightNick) {
new_.get()->GetName() = BufferName;
Players.push_back(new_);
boost::thread(boost::bind(client_session, new_));
PlayersCounter++;
if (PlayersCounter == 1) {
new_.get()->SetHost();
}
}
}
}
Тип PlayersCounter - int
Ответы (2 шт):
Оптимизатор компилятора может вычеркнуть код из-за PlayersCounter. Так как он думает, то эта переменная не меняет значение.
Чтобы стабильно всё работало нужно просто ждать сигнал и использовать мютекс.
std::condition_variable con;
std::mutex mut;
void gm() {
UINT32 lastTick;
// блокируем мютекс
std::unique_lock<std::mutex> lk(mut);
while (true) {
// ждём сигнал
con.wait(lk);
if (PlayersCounter > 0) {
for (auto it = Players.begin(); it < Players.end(); it++) {
if (GameTir == GameTirs::started) {
it->get()->Tick();
}
}
}
//std::cout << "";//Код работает в зависимости от этой строчки, если её нет или она закомментирована, то всё "стоит"
}
}
Чтобы клиенты добавлялись в очередь нужно тоже использовать mutex и кидать сигнал серверу. con.notify_one();
И так, оптимизатор компилятора действительно "не видел" переменные, и скорее всего использовал значения заданные при инициализации. Помог мне шаблон std::atomic<тип>. Можно ли считать это за костыль я не знаю, ибо функция load() скорее всего сжирает не мало ресурсов.