Цикл работает только тогда, когда есть вывод

Есть 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 шт):

Автор решения: AlexGlebe

Оптимизатор компилятора может вычеркнуть код из-за 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() скорее всего сжирает не мало ресурсов.

→ Ссылка