我已經在另一篇文章中問過這個問題,但結果很差,所以我想更好地重新表述。
我必須啟動一系列執行不同任務的執行緒,只有在發送退出信號時才必須回傳,否則(如果它們發生例外或其他任何事情)他們只是從頭開始重新啟動它們的代碼。
為了明確我的意圖,這里有一些代碼:
class thread_wrapper
{
public:
template<typename _Callable, typename... _Args>
thread_wrapper();
void signal_exit() {exit_requested_ = true;}
void join() {th_.join();}
private:
std::thread th_;
bool exit_requested_{false};
void execute()
{
while(!exit_requested_)
{
try
{
// Do thread processing
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
return;
}
};
我想要實作的是使用這個類,因為它是一個普通的 std::thread,在初始化時傳遞一個函式及其引數,但是我希望內部 std::thread 運行“執行”函式,并且僅在 try 塊內我希望它運行在建構式中傳遞的行為。
我怎么能做到這一點?提前致謝。
編輯:我找到了一個解決方案,但我只能在 c 17 中運行(因為 lambda 上的模板),在我看來它并不是那么優雅。
template<typename Lambda>
class thread_wrapper
{
public:
explicit thread_wrapper(Lambda&& lambda) : lambda_{std::move(lambda)}, th_(&thread_wrapper::execute, this){};
void signal_exit() {exit_requested_ = true;}
void join() {th_.join();}
private:
std::thread th_;
bool exit_requested_{false};
Lambda lambda_;
void execute()
{
while(!exit_requested_)
{
try
{
lambda_();
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
return;
}
};
這是一個示例主:
class Foo
{
public:
void say_hello() { std::cout << "Hello!" << std::endl;}
};
int main()
{
Foo foo;
thread_wrapper th([&foo](){foo.say_hello(); std::this_thread::sleep_for(2s);});
std::this_thread::sleep_for(10s);
th.signal_exit();
th.join();
}
你怎么認為?
uj5u.com熱心網友回復:
我會說你找到的解決方案很好。您可能希望避免其thread_wrapper本身成為模板化類,而僅將建構式模板化:
// no template
class thread_wrapper {
public:
template<typename Lambda, typename... Args>
explicit thread_wrapper(Lambda lambda, Args&&... args) {
:lambda_(std::bind(lambda, std::forward<Args>(args)...))
}
// ...
private:
std::function<void()> lambda_;
// ...
};
(我沒有嘗試編譯這個 - 小語法錯誤等是可以預料的。更多的是展示這個概念)
重要提示:如果您呼叫signal_exit,它不會中止 的執行lambda_。它只會在 lambda 回傳/拋出后退出。
需要考慮的兩個小命名事項:
thread_wrapper不是一個偉大的名字。它沒有告訴我們任何關于目的的資訊,也沒有告訴我們它與常規執行緒有什么不同。也許robust_thread(表示自動例外恢復)或其他什么。- 該方法
signal_exit可以命名為exit。沒有理由使此類的介面特定于信號。您可以將此類用于任何應該自動重新啟動的執行緒,直到它被代碼的其他部分告知停止為止。
編輯:我忘記的另一件事,exit_requested_必須是原子的或受互斥鎖保護的,以防止未定義的行為。我建議一個std::atomic<bool>,在你的情況下應該足夠了。
uj5u.com熱心網友回復:
我會為此使用 std::async 和條件變數構造。我將所有條件變數邏輯封裝在一個類中,以便可以輕松重用。有關條件變數的更多資訊:https : //www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables 不要猶豫,要求更多如果你需要它的資訊。
#include <chrono>
#include <future>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <thread>
//-----------------------------------------------------------------------------
// synchronization signal between two threads.
// by using a condition variable the waiting thread
// can even react with the "sleep" time of your example
class signal_t
{
public:
void set()
{
std::unique_lock<std::mutex> lock{m_mtx};
m_signalled = true;
// notify waiting threads that something worth waking up for has happened
m_cv.notify_all();
}
bool wait_for(const std::chrono::steady_clock::duration& duration)
{
std::unique_lock<std::mutex> lock{ m_mtx };
// condition variable wait is better then using sleep
// it can detect signal almost immediately
m_cv.wait_for(lock, duration, [this]
{
return m_signalled;
});
if ( m_signalled ) std::cout << "signal set detected\n";
return m_signalled;
}
private:
std::mutex m_mtx;
std::condition_variable m_cv;
bool m_signalled = false;
};
//-----------------------------------------------------------------------------
class Foo
{
public:
void say_hello() { std::cout << "Hello!" << std::endl; }
};
//-----------------------------------------------------------------------------
int main()
{
Foo foo;
signal_t stop_signal;
// no need to create a threadwrapper object
// all the logic fits within the lambda
// also std::async is a better abstraction then
// using std::thread. Through the future
// information on the asynchronous process can
// be fed back into the calling thread.
auto ft = std::async(std::launch::async, [&foo, &stop_signal]
{
while (!stop_signal.wait_for(std::chrono::seconds(2)))
{
foo.say_hello();
}
});
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "setting stop signal\n";
stop_signal.set();
std::cout << "stop signal set\n";
// synchronize with stopping of the asynchronous process.
ft.get();
std::cout << "async process stopped\n";
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/336860.html
