std::atomic_flag 停止多个线程
std::atomic_flag to stop multiple threads
我正在尝试使用 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;
}
我的问题是上面的"Problem Sector"。即创建线程。我不知道如何实例化线程并将变量传递给工作线程。
现在的错误是引用此行 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));
在第 td->thread = std::thread(&work, i, td->continueFlag);
行给出错误 std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function
。我是否从根本上误解了 std::atomic_flag 的用法?真的既不可移动又不可复制吗?
您的第一种方法实际上更接近事实。问题是它将对局部 for
循环范围内的对象的引用作为参数传递给每个线程。但是,当然,一旦循环迭代结束,该对象就会超出范围并被销毁,从而使每个线程都有对已销毁对象的引用,从而导致未定义的行为。
没有人关心您在创建线程后将对象移入 std::vector
的事实。该线程收到了对局部范围对象的引用,这就是它所知道的全部内容。故事结束。
首先将对象移动到向量中,然后将对 std::vector
中的对象的引用传递给每个线程也不会起作用。一旦 vector 在内部重新分配,作为其自然增长的一部分,您将处于同一个泡菜中。
需要做的是在实际开始任何 std::thread
之前先创建整个 threads
数组。如果虔诚地遵循 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));
}
}
我正在尝试使用 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;
}
我的问题是上面的"Problem Sector"。即创建线程。我不知道如何实例化线程并将变量传递给工作线程。
现在的错误是引用此行 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));
在第 td->thread = std::thread(&work, i, td->continueFlag);
行给出错误 std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function
。我是否从根本上误解了 std::atomic_flag 的用法?真的既不可移动又不可复制吗?
您的第一种方法实际上更接近事实。问题是它将对局部 for
循环范围内的对象的引用作为参数传递给每个线程。但是,当然,一旦循环迭代结束,该对象就会超出范围并被销毁,从而使每个线程都有对已销毁对象的引用,从而导致未定义的行为。
没有人关心您在创建线程后将对象移入 std::vector
的事实。该线程收到了对局部范围对象的引用,这就是它所知道的全部内容。故事结束。
首先将对象移动到向量中,然后将对 std::vector
中的对象的引用传递给每个线程也不会起作用。一旦 vector 在内部重新分配,作为其自然增长的一部分,您将处于同一个泡菜中。
需要做的是在实际开始任何 std::thread
之前先创建整个 threads
数组。如果虔诚地遵循 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));
}
}