簡體   English   中英

std :: atomic_flag停止多個線程

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM