[英]std::atomic_flag to stop multiple threads
我正在嘗試使用std::atomic_flag
停止多個工作線程。 從問題開始, 使用帶有工作線程的std :: atomic_flag進行以下工作:
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
std::atomic_flag continueFlag;
std::thread t;
void work()
{
while (continueFlag.test_and_set(std::memory_order_relaxed)) {
std::cout << "work ";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void start()
{
continueFlag.test_and_set(std::memory_order_relaxed);
t = std::thread(&work);
}
void stop()
{
continueFlag.clear(std::memory_order_relaxed);
t.join();
}
int main()
{
std::cout << "Start" << std::endl;
start();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Stop" << std::endl;
stop();
std::cout << "Stopped." << std::endl;
return 0;
}
嘗試重寫為多個工作線程:
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>
#include <memory>
struct thread_data {
std::atomic_flag continueFlag;
std::thread thread;
};
std::vector<thread_data> threads;
void work(int threadNum, std::atomic_flag &continueFlag)
{
while (continueFlag.test_and_set(std::memory_order_relaxed)) {
std::cout << "work" << threadNum << " ";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void start()
{
const unsigned int numThreads = 2;
for (int i = 0; i < numThreads; i++) {
////////////////////////////////////////////////////////////////////
//PROBLEM SECTOR
////////////////////////////////////////////////////////////////////
thread_data td;
td.continueFlag.test_and_set(std::memory_order_relaxed);
td.thread = std::thread(&work, i, td.continueFlag);
threads.push_back(std::move(td));
////////////////////////////////////////////////////////////////////
//PROBLEM SECTOR
////////////////////////////////////////////////////////////////////
}
}
void stop()
{
//Flag stop
for (auto &data : threads) {
data.continueFlag.clear(std::memory_order_relaxed);
}
//Join
for (auto &data : threads) {
data.thread.join();
}
threads.clear();
}
int main()
{
std::cout << "Start" << std::endl;
start();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Stop" << std::endl;
stop();
std::cout << "Stopped." << std::endl;
return 0;
}
我的問題是上面的“問題部門”。 即創建線程。 我不能全神貫注於如何實例化線程並將變量傳遞給工作線程。
現在的錯誤是引用此行threads.push_back(std::move(td));
Error C2280 'thread_data::thread_data(const thread_data &)': attempting to reference a deleted function
。
嘗試像這樣使用unique_ptr:
auto td = std::make_unique<thread_data>();
td->continueFlag.test_and_set(std::memory_order_relaxed);
td->thread = std::thread(&work, i, td->continueFlag);
threads.push_back(std::move(td));
給出錯誤std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function
在行td->thread = std::thread(&work, i, td->continueFlag);
處std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function
td->thread = std::thread(&work, i, td->continueFlag);
。 我是否從根本上誤解了std :: atomic_flag的使用? 真的既不可移動又不可復制嗎?
您的第一種方法實際上更接近事實。 問題在於,它將對本地for
循環范圍內的對象的引用作為參數傳遞給了每個線程。 但是,當然,一旦循環迭代結束,該對象就會超出范圍並被銷毀,從而使每個線程都具有對銷毀對象的引用,從而導致未定義的行為。
沒有人關心創建線程后將對象移動到std::vector
的事實。 該線程收到了對本地作用域對象的引用,僅此而已。 故事結局。
首先將對象移動到向量中,然后將對std::vector
對象的引用傳遞給每個線程也將不起作用。 向量在內部重新分配后,作為其自然增長的一部分,您將處在相同的泡菜中。
需要做的是先創建整個threads
數組,然后再實際啟動任何std::thread
。 如果嚴格遵守RAII原則,則僅意味着對std::vector::resize()
的簡單調用。
然后,在第二個循環中,遍歷完全煮熟的threads
數組,然后為該數組中的每個元素生成一個std::thread
。
我的unique_ptr
解決方案幾乎在那兒。 我只需要像這樣將調用作為std :: ref()傳遞:
std::vector<std::unique_ptr<thread_data>> threads;
void start()
{
const unsigned int numThreads = 2;
for (int i = 0; i < numThreads; i++) {
auto td = std::make_unique<thread_data>();
td->continueFlag.test_and_set(std::memory_order_relaxed);
td->thread = std::thread(&work, i, std::ref(td->continueFlag));
threads.push_back(std::move(td));
}
}
但是,受以上所述的Sam啟發,我還想出了一種非指針方式:
std::vector<thread_data> threads;
void start()
{
const unsigned int numThreads = 2;
//create new vector, resize doesn't work as it tries to assign/copy which atomic_flag
//does not support
threads = std::vector<thread_data>(numThreads);
for (int i = 0; i < numThreads; i++) {
auto& t = threads.at(i);
t.continueFlag.test_and_set(std::memory_order_relaxed);
t.thread = std::thread(&work, i, std::ref(t.continueFlag));
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.