【发布时间】:2021-10-28 01:06:40
【问题描述】:
假设我有一个客户端线程和一个服务器线程。客户端线程必须执行昂贵的 for 循环操作,这很容易挂起。这样,服务器就可以独立判断for循环的每个tick是否超过了最大时间。这背后的背景是,如果完成一个滴答的时间过长,服务器将使客户端超时。
我最初的想法是在客户端和服务器线程中有两个 for 循环。服务器线程将有一个等待 1 秒的条件变量。如果客户端在每个tick的1秒内没有通知条件变量,服务端会超时:
服务器
bool success;
for (int i = 0; i < 10; i++) {
std::unique_lock<std::mutex> lock(CLIENT_MUTEX);
success = CLIENT_CV.wait_for(lock, std::chrono::seconds(1));
if (!success) {
std::cout << "timed out during tick " << i << std::endl;
break;
}
}
客户
for (int i = 0; i < 10; i++) {
std::unique_lock<std::mutex> lock(CLIENT_MUTEX);
//do work
CLIENT_CV.notify_one();
}
但是,考虑到客户端的相同工作,我的实现尝试是不可靠的,并且会随机超时。如何改进设计以使其更可靠?
旁注:
一个简单的解决方案是让服务器对整个 for 循环而不是每个滴答计时。但是,如果 for 循环在 10 次中的第 1 次失败,并且计时器正在等待 10 秒,则将在 10 秒后通知客户端。但是,如果服务器对每个滴答(10x1sec = 10 秒)施加 1 秒超时,则客户端将被通知超时,而无需等待整整 10 秒。
编辑。
整个客户端/服务器/超时的类比只是将问题置于上下文中。我完全对从不同线程计时 for 循环的最佳方法感兴趣。
【问题讨论】:
-
不可靠到底是什么意思?如果它随机超时,这可能只是表明工作需要大约 1 秒并且触发超时的次数相当多(即对于需要 0.8+-0.1 秒的任务,您预计大约 50 分之一会超时如果超时是 1 秒),或者它没有计时 1 秒但有时会在 0.1 秒后超时?
-
@RichardCritten 超时部分不是问题的一部分。我只是对为 for 循环的每个滴答计时的最佳方法感兴趣。在我真正的问题中,它没有超时。我只是想表明对这个过程进行计时很重要。
-
这是一个 XY 问题,真正的问题是如何通知/终止客户端线程?如果通知客户端线程关闭,则客户端线程必须循环和轮询(在工作期间),并且它可以根据作为工作包的一部分传递给它的超时来关闭自己。如果客户端线程是硬循环(而不是轮询),那么在客户端线程完成工作之前,无法彻底关闭它。无论哪种方式,都不需要从服务器线程监视客户端线程。
-
@RichardCritten 我只是想把问题放到上下文中。我的真正问题不涉及服务器或客户端。标题为“在另一个线程中独立计时 For 循环的每个 Tick 的最佳方法”。我现在已经在问题中澄清了这一点。
-
你可以实现一个账本,它在每个滴答声(以及整个循环之后)接收一个
std::chrono::time_point,它会为每个滴答声计时。您可以将此分类帐提供给定期检查此分类帐的其他线程并休眠,以便在它期望下一个条目时唤醒它,而当它没有时它可以设置一些标志,但我不确定这是否是“最好的办法。不过,我也认为不需要其他线程。
标签: c++ multithreading timeout thread-safety