c++ - 如何发出一个线程正确结束的信号
问题描述
所以我正在做一个学校项目来模拟实时自动战斗。代码是这样的:
void attack(Fighter& f1, Fighter& f2)
{
while (!f1.is_down()&&!f2.is_down())
{
this_thread::sleep_for(chrono::seconds(f1.get_spd())/10);
cout << f1.get_name() << " dealt " << f2.get_dmg(f1) << " damage" << endl;
}
if (f2.is_down()) cout << '\t' << f2.get_name() << "is defeated" << endl;
}
void Fight::fight_start()
{
thread f1_attack(attack, f1, f2);
thread f2_attack(attack, f2, f1);
f1_attack.join();
f2_attack.join();
}
战斗应该在一方被击败时结束,但他们会继续战斗直到双方都失败。如何阻止被击落的战斗机继续战斗?
编辑:我修好了。
解决方案
在 C++ 中,如果一个线程修改数据,任何读取器都必须以某种方式同步。如果不是,您的程序的行为不是由 C++ 标准定义的,这很糟糕。
我认为您在这里使用线程的方式在某些方面是不好的。
您的访问权限是 UB,或者您正在使用每个对象的锁定。第一个意味着你的程序被彻底破坏了;第二种是一种不组合的多线程编程。(不组合意味着两个“正确”的代码,当连接时,就问题而言可能是不正确的。)
您正在花费一个昂贵的线程作为美化的计时器。
您正在从多个线程执行非同步 io。
即使您对每个方法都进行了互斥锁定,您的线程代码也会被破坏。例如,死去的战士可以攻击。
我会在这里做的是:
制作一个调度器。它有一个排序的双端队列或多映射(关键是时间)要做的任务。当您添加任务时,您会说您希望它们何时弹出。当你等待任务时,它会让你等到有一个时间到了。
也许是这样的:
struct scheduler{
using clock=std::chrono::steady_clock;
using time_point=clock::time_point;
using task=std::function<void(time_point)>;
task pop();
void push(time_point, task);
void push_now(task){ push(clock::now(), std::move(task)); }
private:
mutable std::mutex m;
std::condition_variable cv;
std::multimap<clock::time_point, task> queue;
};
你的战士“线程”不再是线程。
scheduler fight;
fight.push_now([&](auto when){
round(fight, when, f1, f2);
});
fight.push_now([&](auto when){
round(fight, when, f2, f1);
});
while(auto f=fight.pop()){
f();
}
回合可能是:
void round(scheduler& fight, scheduler::time_point when, fighter& attacker, fighter& defender){
if (!attacker.is_down()&&!defender.is_down()){
std::cout<<attacker.name()<< " hits "<< defender.name() << " for " << attacker.do_dmg(defender) <<"\n";
}
if (defender.is_down()){
std::cout<<defender.name()<<" defeated.";
}
if (attacker.is_down()){
std::cout<<attacker.name()<<" defeated.";
}
if Iattacker.is_down()||defender.is_down())
fight.push_now({});// end
else
fight.push(when+chrono::seconds(f1.get_spd()/10.), [&](auto when){round(fight, when, attacker, defender);});
}
如果需要,调度程序可以在线程中运行。
可能有错别字。而且您必须研究如何使用条件变量休眠,直到超时或推送新内容的通知。
推荐阅读
- android - 是否可以使用存储访问框架实现 Google Drive 文件夹选择器对话框?
- web-crawler - UnicodeDecodeError:“utf-8”编解码器无法解码位置 10208 中的字节 0xa0:无效的起始字节
- docker - 如何以非 root 用户身份构建 go docker 映像?
- json - 使用 jq 的 json 到 csv 问题
- javascript - 按键获取对象,保持键位
- python - 我们如何编写一个函数来获取文件名并在 pandas 中创建数据框?(没有 pandas 内置函数)
- asp.net -
我试图弄清楚这是如何工作的。在来自 VS 模板(Web 表单)的站点主文件中,我阅读了以下内容:
<asp:ScriptManager runat="server"> <Scripts> <asp:ScriptR
- c++ - C++ 递归函数
- python - 诗歌虚拟环境已激活
- reactjs - useEffect 操纵次要值