独立计时另一个线程中 For 循环的每个滴答的最佳方法
Best approach to Independently Timing each Tick of a For Loop in another Thread
假设我有一个客户端线程和一个服务器线程。客户端线程必须执行昂贵的 for 循环操作,这很容易挂起。这样,服务器就独立判断了for循环的每个tick是否超过了最大时间。这背后的上下文是,如果完成一个 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 循环计时,而不是为每个 tick 计时。但是,如果 for 循环在 10 次中的第 1 次失败,并且计时器正在等待 10 秒,那么客户端将在 10 秒后收到通知。但是,如果服务器为每个滴答 (10x1sec = 10secs) 施加 1 秒超时,则客户端将被通知超时,而无需等待整整 10 秒。
编辑。
整个client/server/timeout类比只是将问题放在上下文中。我纯粹对从不同线程为 for 循环计时的最佳方式感兴趣。
一种方法可能是:
共享变量:
std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>> ledger;
std::mutex ledger_mtx;
客户:
for (int i = 0; i < 10; i++) {
{
std::scoped_lock lock(ledger_mtx);
ledger.push_back(std::chrono::high_resolution_clock::now());
}
// Do work
}
{
std::scoped_lock lock(ledger_mtx);
ledger.push_back(std::chrono::high_resolution_clock::now());
}
服务器:
size_t id = 0;
std::this_thread::wait_for(1s); // Some time so that initial write to ledger is made
while(true) {
{
std::scoped_lock lock(ledger_mtx);
if(ledger.size()==id) { /* Do something if the thread hangs */ }
id = ledger.size();
std::chrono::time_point<std::chrono::high_resolution_clock> last_tick = ledger.back();
}
if(id == 11) break;
std::this_thread::sleep_for(1s - (std::chrono::high_resolution_clock::now() - last_tick));
}
这样您可以在从外部监视线程的同时为线程计时。这是最好的方法吗?可能不会,但它确实为您提供了所需的时间。
假设我有一个客户端线程和一个服务器线程。客户端线程必须执行昂贵的 for 循环操作,这很容易挂起。这样,服务器就独立判断了for循环的每个tick是否超过了最大时间。这背后的上下文是,如果完成一个 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 循环计时,而不是为每个 tick 计时。但是,如果 for 循环在 10 次中的第 1 次失败,并且计时器正在等待 10 秒,那么客户端将在 10 秒后收到通知。但是,如果服务器为每个滴答 (10x1sec = 10secs) 施加 1 秒超时,则客户端将被通知超时,而无需等待整整 10 秒。
编辑。
整个client/server/timeout类比只是将问题放在上下文中。我纯粹对从不同线程为 for 循环计时的最佳方式感兴趣。
一种方法可能是:
共享变量:
std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>> ledger;
std::mutex ledger_mtx;
客户:
for (int i = 0; i < 10; i++) {
{
std::scoped_lock lock(ledger_mtx);
ledger.push_back(std::chrono::high_resolution_clock::now());
}
// Do work
}
{
std::scoped_lock lock(ledger_mtx);
ledger.push_back(std::chrono::high_resolution_clock::now());
}
服务器:
size_t id = 0;
std::this_thread::wait_for(1s); // Some time so that initial write to ledger is made
while(true) {
{
std::scoped_lock lock(ledger_mtx);
if(ledger.size()==id) { /* Do something if the thread hangs */ }
id = ledger.size();
std::chrono::time_point<std::chrono::high_resolution_clock> last_tick = ledger.back();
}
if(id == 11) break;
std::this_thread::sleep_for(1s - (std::chrono::high_resolution_clock::now() - last_tick));
}
这样您可以在从外部监视线程的同时为线程计时。这是最好的方法吗?可能不会,但它确实为您提供了所需的时间。