samedi 27 février 2016

std::atomic_flag to stop multiple threads

I'm trying to stop multiple worker threads using a std::atomic_flag. Starting from Issue using std::atomic_flag with worker thread the following works:

#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;
}

Trying to rewrite into multiple worker threads:

#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;
}

My issue is "Problem Sector" in above. Namely creating the threads. I cannot wrap my head around how to instantiate the threads and passing the variables to the work thread.

The error right now is referencing this line threads.push_back(std::move(td)); with error Error C2280 'thread_data::thread_data(const thread_data &)': attempting to reference a deleted function.

Trying to use unique_ptr like this:

        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));

Gives error std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function at line td->thread = std::thread(&work, i, td->continueFlag);. Am I fundamentally misunderstanding the use of std::atomic_flag? Is it really both immovable and uncopyable?

Aucun commentaire:

Enregistrer un commentaire