在 C++ 中,如何生成每 5 分钟更改一次的随机数(1 或 2)?
Posted
技术标签:
【中文标题】在 C++ 中,如何生成每 5 分钟更改一次的随机数(1 或 2)?【英文标题】:In C++, how would I make a random number (either 1 or 2) that changes every 5 minutes? 【发布时间】:2014-06-24 21:55:51 【问题描述】:我正在尝试制作一个简单的游戏,并且我在游戏中有一个商店。我希望它每 5 分钟(如果调用函数 changeItem() )商店中的商品要么切换一次,要么保持不变。我生成随机数没有问题,但我还没有找到一个线程来说明如何让它每 5 分钟生成一次。谢谢。
【问题讨论】:
这不应与系统时钟相关联,而应与“游戏时间”相关联,即在游戏环境中经过了多少时间。您需要做的就是检查(可能在确定商店内容的函数中)自上次检查商店内容以来经过了多少游戏时间,如果时间足够长,则重新滚动。 尝试调用 srand(time(NULL));在调用 rand() 之前。 同意@Zack;将定时器或线程引入架构中只是为了做到这一点几乎可以肯定是错误的方法。 【参考方案1】:简而言之,跟踪上次调用 changeItem()
函数的时间。如果距离上次调用超过 5 分钟,则使用您的随机数生成器生成一个新数字。否则,使用上次生成时保存的编号。
【讨论】:
【参考方案2】:您已经接受了一个答案,但我想说,对于需要像这样简单的计时并且不需要很高的准确性的应用程序,只需在主循环中进行简单的计算即可。
为单个计时器启动一个线程是很多不必要的开销。 所以,这里的代码展示了你将如何去做。
#define FIVE_MINUTES (60*5)
int main(int argc, char** argv)
time_t lastChange = 0, tick;
run_game_loop = true;
while (run_game_loop)
// ... game loop
tick = time(NULL);
if ((tick - lastChange) >= FIVE_MINUTES)
changeItem();
lastChange = tick;
return 0;
虽然它在某种程度上假设被合理地定期调用。另一方面,如果您需要它准确,那么线程会更好。并且根据平台的不同,存在由系统调用的计时器 API。
【讨论】:
我同意计时器。不幸的是,这些论文是不可移植的。另一方面,如果目标是制作游戏,那么使用线程是一种有效的架构。最后但并非最不重要的一点是,您的循环使处理器忙于计算时间。使用 sleeps() 的线程方法可以在不需要提高其他任务的性能并降低便携式设备的电池消耗时释放 CPU。 @Christophe - 您可能认为线程化方法使 CPU 更忙,但实际上与游戏逻辑的其余部分相比,time(NULL) 和一些检查是如此之小以至于不是如您所想的性能瓶颈。我的方法也可以扩展到其他计时任务。除非您使线程通用,否则您必须使用循环创建另一个线程。您还忘记了线程的上下文切换。这可能会否定我的测试,甚至可能比时间(NULL)更重。我认为这两种方法都不会或多或少地使您的笔记本电脑电池变平。 @Christophe - 如果我绝对需要一个非常准确的时间,我会使用你的方法。如果需要,我们可以使用提供跨平台计时器的框架。 +1 用于框架。关于上下文切换,线程是轻量级的(它不是具有自己环境的完整任务):切换只是将寄存器存储在单核处理器上,因此与函数调用无关。无论如何,现在大多数 CPU 都是多核的(即硬件中的多线程)。我对 CPU 消耗的看法不在游戏内,但一般来说,PC/或智能手机可能会执行与游戏无关的并发任务)。但是您的解决方案非常适合传统的游戏循环架构:-)【参考方案3】:标准且可移植的方法:
您可以考虑 C++11 线程。一般的想法是:
#include <thread>
#include <chrono>
void myrandogen () // function that refreshes your randum number:
// will be executed as a thread
while (! gameover )
this_thread::sleep_for (std::chrono::minutes(5)); // wait 5 minutes
... // generate your random number and update your game data structure
在主函数中,您将使用您的函数实例化一个线程:
thread t1 (myrandomgen); // create an launch thread
... // do your stuff until game over
t1.join (); // wait until thread returns
当然,您也可以在创建线程时传递参数(对共享变量的引用等),如下所示:
thread t1 (myrandomgen, param1, param2, ....);
这种方法的优点是它是标准的和可移植的。
非便携式替代品:
我对这些不太熟悉,但是:
在 MSWIN 环境中,您可以使用 SetTimer(...) 定义要定期调用的函数(并使用 KillTimer(...) 删除它)。但这需要围绕 Windows 事件处理循环构建程序结构。
在 linux 环境中,您可以类似地使用 signal(SIGALRM, ...) 定义回调函数,并使用 alarm() 激活定期调用。
关于性能考虑的小更新: 在几次关于过度杀伤和性能的 reamrks 之后,我做了一个基准测试,执行 10 亿次循环迭代,每 100K 次迭代等待 1 微秒。整个过程在 i7 多核 CPU 上运行:
非线程执行每毫秒产生 213K 次迭代。
2 线程执行每毫秒和每个线程产生 209K 次迭代。所以每个线程都稍微慢一点。然而,总执行时间仅长 70 到 90 毫秒,因此总吞吐量为 418 K 迭代。
怎么会?因为第二个线程正在处理器上使用未使用的内核。这意味着有了足够的架构,游戏在使用多线程时可以处理更多的计算......
【讨论】:
不客气!如果它对您有所帮助,请不要犹豫将答案标记为“已接受”(另请参阅:***.com/tour);-) 能否请对这个可行的解决方案投反对票的人解释原因并给我改进的机会? 为单个计时器滥用线程是矫枉过正的。尤其是在游戏环境中,无论如何几乎总是有一个固定速率的主循环,其运行频率远高于此处所需的 5 分钟。 @Matt 我没有怀疑你:你的回答很有价值,所以我认为你会发现我的回答是相关的,即使我们不完全同意什么是终极方法;-) @MSalters 5 分钟你是对的。但是我的回复有两部分:最标准的部分(您批评的线程)和性能最高的非标准部分(win 中的计时器和 linux 中的警报):您认为两者都是不好的响应吗??以上是关于在 C++ 中,如何生成每 5 分钟更改一次的随机数(1 或 2)?的主要内容,如果未能解决你的问题,请参考以下文章