线程未正确结束:它忽略失败的循环条件

Threads doesn't end correctly: it ignores failing loop conditions

本文关键字:失败 循环 条件 结束 线程      更新时间:2023-10-16

我正在研究一个小的战斗代码,试图学习在 c++ 中使用线程,但偶然发现了一个我无法弄清楚的错误。

我使用多文本进行同步:

mutex mux1;

和一个线程函数:

void dueler(Player &player, Player &enemy)
{
     do
     {
          Sleep(player.get_as());
          mux1.lock();
          cout << player.get_name()<< " hit " << enemy.get_name() << " for " << player.get_str() << " damage!" << endl;
          enemy.dmg(player.get_str());
          mux1.unlock();
     } while ((enemy.ask_dead() != true) && (player.ask_dead() != true));
 }

我在main中调用(完整代码:http://pastebin.com/1FBf2FCQ):

int main()
{
    Player Player1("kasper", 100, 5, 200);
    Player Player2("Bagger", 150, 8, 3000);
    thread dueler1(dueler,Player1,Player2);
    thread dueler2(dueler, Player2, Player1);
    dueler1.join();
    dueler2.join();
    cout <<endl<< "battle is over!";
}

线程函数使玩家(http://pastebin.com/ZCTfUYiS)相互对抗:

class Player
{
public:
    Player(string name_, int maxhp_, int strenght_, int attackspeed_) {
        name = name_; 
        maxhp = maxhp_; 
        hp = maxhp;
        strenght = strenght_;
        attackspeed = attackspeed_;
        isdead = false;
    }
    void fullhp() {  hp = maxhp;  }
    void dmg(int dmg) {
        hp -= dmg;
        if (hp < 0) dead();
    }
    void dead() {
        isdead = true;
        cout << name <<" died like a pessant";
    }
    string get_name() { return name; }
    int get_hp()    { return hp; }
    int get_maxhp() { return maxhp; }
    int get_str()   { return strenght; }
    int get_as()    { return attackspeed; }
    bool ask_dead() {return isdead; }
private:
    string name;
    int maxhp;
    int hp;
    int strenght;
    int attackspeed;
    bool isdead;
};

Player2被杀时,就会出现问题:

  • 线程 1(处理玩家 1 造成的伤害)按原样停止,
  • 线程 2(处理Player2谁死了)继续运行,并完全忽略 while 语句,直到玩家 1 死了。

我本以为while会因为条件而结束(player.ask_dead() != true)应该失败。

有什么建议吗?

通过放置 mutext 来正确完成同步,以避免并发访问您的对象。这已经是一个非常好的开始了!

问题:

问题是,当您创建线程时,它会创建您传递的参数的私有副本(另请参阅此相关 SO 问题)

您可以通过在 dueller() 中添加第一个语句来轻松验证引用:

cout << "dueller with player " << (void*)&player << " and ennemy " << (void*)&enemy << endl;

当通过引用使用参数调用dueler()时,引用不是指原始对象(main()中的局部变量),而是引用其克隆。

解决方案:

您必须使用 std::ref() 来确保所有线程确实引用相同的对象:

thread dueler1(dueler, std::ref(Player1), std::ref(Player2));
thread dueler2(dueler, std::ref(Player2), std::ref(Player1));

其他备注:

当玩家死亡时,他的dueler()功能很可能在等待互斥锁。 因此,当互斥体获得自由时,尽管他已经死了,但他还是会执行损害赔偿。

好的!在游戏中,你可以争辩说玩家已经死了,但仍然带着这把剑向受害者跑去......但是我们也可以通过在进入保护区时添加一个条件来修复它:

    mux1.lock();  // we were waiting, a certain time
    if (!player.ask_dead()) {  // so first check if we are still alive
        cout << player.get_name() << " hit " << enemy.get_name() << " for " << player.get_str() << " damage!" << endl;
        enemy.dmg(player.get_str());
    }
    mux1.unlock();