将来尝试引用已删除的函数

Attempting to Reference a Deleted Function in Future

我正在编写一个程序,它将异步查找大量质数。我通过使用 TaskQueue 来实现,它本质上是一个 queue ,由所有异步执行的期货组成。涉及三个线程:将这些任务分配给 TaskQueue 的厨师线程,检查期货是否有答案并决定是否存储数据的客户线程,以及启动的主线程并检查其他两个的状态。我在第 593 行收到错误:Error 2 error C2280: 'std::future<return_type>::future(const std::future<return_type> &)' : attempting to reference a deleted function e:\visualstudio\vc\include\xmemory0 593 1 MultiThreadTaskQueue 引用文件 xmemory0,它似乎是我 #included 的另一个 headers 引用的文件。我的问题似乎是未来 object 的复制构造函数的问题,可能是在复制之前被删除的复制构造函数,但我不确定在我的程序中会发生什么。这是我的代码的副本:

#include <iostream>
#include <queue>
#include <future>
#include <thread>
#include <vector>
#include <mutex>

using namespace std;
using longInt = long long unsigned int;

template <typename return_type>
class TaskQueue {
private:
    queue<future<return_type>> tasks;
    mutex mtx;

public:
    //return a copy of the queue
    queue<future<return_type>> copy() const {
        return tasks;
    }


    //default constructor
    //does nothing, waits for input
    TaskQueue() {
        //do nothing
    }

    //call constructors
    //adds task to queue
    template <typename ... Args, typename ... Ts>
    TaskQueue(return_type(*func)(Ts...), Args&& ... args) {
        tasks.push(std::async(func, args...));
    }

    //copy constructor
    //copies another queue to this one
    TaskQueue(const TaskQueue<longInt> & in) {
        tasks = in.copy();
    }

    //setter and getter functions

    //inserts a new task into the queue
    template <typename ... Args, typename ... Ts>
    void add(return_type(*func)(Ts...), Args&& ... args) {
        tasks.push(std::async(func, args...));
    }

    //returns true if the task at the top of the queue is ready
    bool valid() {
        return tasks.front().valid();
    }

    //gets the value, if the value is not ready, waits for it to be ready
    //pops the top task after getting it
    return_type get() {
        //mtx.lock();

        return_type temp = tasks.front().get();

        tasks.pop();

        //mtx.unlock();
        return temp;
    }

    //waits for the value of the top of the queue to become ready
    void wait() {
        tasks.front().wait();
    }

    //returns the number of tasks in the queue
    int size() const {
        return tasks.size();
    }

};

bool HALT_ALL = false;
int MAX_TASKS_AT_ONCE = 10;

//prototypes
longInt isPrime(longInt);
void cook(TaskQueue<longInt>&);
void consumer(TaskQueue<longInt>&, vector<longInt> &);

int main() {

    //declare task queue and vector to store prime numbers
    TaskQueue<longInt> checkPrimes;
    vector<longInt> primes;
    primes.push_back(2);

    int maxPrimes;

    cout << "Enter max primes: ";
    cin >> maxPrimes;
    cout << endl;



    //launch the chef thread and the customer thread
    thread chef(&cook, checkPrimes);
    thread customer(&consumer, checkPrimes, primes);

    int previousSize = 0;

    //use main to keep track of the progress of the other threads
    while (primes.size() < maxPrimes) {
        if (previousSize != primes.size()) {
            cout << "Primes found: " << primes.size() << endl;
            previousSize = primes.size();
        }
        else {
            checkPrimes.wait();
        }
    }

    //halt all other asynchronous operations
    HALT_ALL = true;

    //join other threads
    chef.join();
    customer.join();

    //print final prime found for verification of data
    cout << "Final Prime found: " << primes[primes.size() - 1] << endl;

    system("PAUSE");


    return 0;

}

//returns the number if it is prime or 0 if it is not
longInt isPrime(longInt n) {
    if (n <= 3) {
        if (n > 1) {
            return n;
        }
        return 0;
    }

    if (n % 2 == 0 || n % 3 == 0) {
        return 0;
    }

    for (unsigned short i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return 0;
        }
    }

    return n;
}

void cook(TaskQueue<longInt>& tasks) {
    longInt currentPrime = 3;

    while (!HALT_ALL) {
        if (tasks.size() < MAX_TASKS_AT_ONCE) {
            tasks.add(isPrime, currentPrime);
            currentPrime += 2;
        }
    }
}

void consumer(TaskQueue<longInt>& tasks, vector<longInt> & primes) {
    while (!HALT_ALL) {
        if (tasks.size() > 0) {
            longInt temp = tasks.get();

            if (temp > 0) {
                primes.push_back(temp);
            }
        }
    }
}

您正试图在此处复制 std::future

queue<future<return_type>> copy() const {
    return tasks;
}

但是 std::future 是 non-copyable,它的复制构造函数被删除(参见示例 here),所以您会收到编译器错误消息。

删除 copy() 函数和 TaskQueue 复制构造函数。

其实你的错误就在这里:

thread chef(&cook, checkPrimes);
thread customer(&consumer, checkPrimes, primes);

如果参数是右值,std::thread 构造函数移动它的参数,否则复制它们。所以只需传递 reference_wrappers 即可:

thread chef(&cook, std::ref(checkPrimes));
thread customer(&consumer, std::ref(checkPrimes), std::ref(primes));

它不仅可以编译您的代码,还可以使代码在语义上更正确,因为您可能不希望每个线程都有自己的任务队列和素数向量。

请注意,您必须进行适当的同步以避免数据竞争。