C ++ Implementierung einer Timeout-Funktionsvorlage für Klassenmethoden
Das Ziel, das ich erreichen möchte, ist, dass das Programm den Prozess stoppt und einen Timeout-Fehler zurückgibt, wenn der Prozess die Timeout-Zeit überschreitet.
Ich habe eine Timeout-Funktion von der zweithäufigsten Antwort auf diese Frage erhalten . Ich bin auf einen Fehler gestoßen, der besagt, dass er std::result_of_tin C ++ 17 veraltet ist. Deshalb habe ich ihn mit dem vorgeschlagenen Ersatz neu erstellt std::invoke_result_tund wie folgt implementiert:
template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
using R = std::invoke_result_t<TF&&, TArgs&&...>;
std::packaged_task<R(TArgs...)> task(f);
auto future = task.get_future();
std::thread thr(std::move(task), std::forward<TArgs>(args)...);
if (future.wait_for(timeout) != std::future_status::timeout)
{
thr.join();
return future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
}
Ich wollte es verwenden, um die Funktion einer Klassenmethode auf Zeitüberschreitung zu überprüfen. Also habe ich versucht, es auf ähnliche Weise zu verwenden:
template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> ClassOne::run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
using R = std::invoke_result_t<TF&&, TArgs&&...>;
std::packaged_task<R(TArgs...)> task(f);
auto future = task.get_future();
std::thread thr(std::move(task), std::forward<TArgs>(args)...);
if (future.wait_for(timeout) != std::future_status::timeout)
{
thr.join();
return future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
}
// The function checked for timeout
int ClassOne::func(ClassTwo *param1, std::string name)
{
// Some code here...
// For mimicking function process:
std::this_thread::sleep_for(10s);
return 0;
}
// Function which calls the timed process with timeout function
int ClassOne::dummy(ClassTwo *param1, std::string name)
{
int retVal = 0; // zero for no error, non-zero for error
try
{
retVal = run_with_timeout(func, 20s, param1, name);
}
catch (runtime_error & e)
{
return 1;
}
}
Damit bekomme ich den Fehler:
no instance of function template "ClassOne::run_with_timeout" matches the argument list
argument types are: (int (ClassTwo *param1, std::string target), std::chrono::seconds, ClassTwo *, std::string)
Ich denke, das Problem ähnelt diesem Eintrag, aber ich habe keine Ahnung, wie ich es beheben soll. Einige Funktionen, für die ich die Timeout-Funktion verwenden muss, haben unterschiedliche Objektparameter, weshalb eine Funktionsvorlage verwendet wird.
Vielen Dank im Voraus für die Hilfe!
Antworten
Wie der Name schon sagt, std::invoke_result_tist die Ergebnisart der Anwendung std::invoke. Ich habe den Fall hervorgehoben, der hier auf Sie zutrifft:
INVOKE (f, t1, t2, ..., tN) ist wie folgt definiert:
...
Wenn f ein Zeiger auf die Mitgliedsfunktion der Klasse T ist:
- Wenn std :: is_base_of <T, std :: zerfall_t <decltype (t1) >> :: value wahr ist, dann ist INVOKE (f, t1, t2, ..., tN) äquivalent zu (t1. * F) ( t2, ..., tN)
- Wenn t1 die vorherigen Punkte nicht erfüllt, entspricht INVOKE (f, t1, t2, ..., tN) ((* t1). * F) (t2, ..., tN).
Ihr Anruf sollte also lauten:
retVal = run_with_timeout(&ClassOne::func, 20s, this, std::move(param1), std::move(name));
EDIT: Ich hatte gut zwanzig Minuten damit zu kämpfen, dass es tatsächlich funktioniert. Durch Hinzufügen std::movewie oben ODER namedurch Konstantenreferenz (in dummy) wird es kompiliert. Ich kann mir keine ähnliche Transformation für vorstellen param1. Es würde mich sehr interessieren, den Grund für diesen Fehler zu kennen, aber zumindest Ihr unmittelbares Problem ist gelöst.