使用std :: future / std :: async

时间:2017-09-04 06:10:43

标签: c++ asynchronous future

当我尝试运行下一个代码时出现了一些错误:

// tree.cpp
// compile with: g++ -std=c++11 tree.cpp -o tree

#include <iostream>
#include <future>

using namespace std;

int valtab[127]; // used for integer values of variables

class Tree; // forward declare

class Node {
protected:
    Node() { use = 1; }
    virtual void print(ostream &os) = 0;
    virtual ~Node() { }
    virtual int eval() = 0;
private:
   friend class Tree;
   friend ostream& operator<<(ostream&, const Tree&);
   int use; // reference count
};

class Tree {
public:
    Tree(int n); // constant
    Tree(char id); // variable
    Tree(char op, Tree t); // unary operator
    Tree(char op, Tree left, Tree right); // binary operator
    Tree(const Tree &t) { p = t.p; ++p->use; }
    ~Tree() { if (--p->use == 0) delete p; }
    void operator=(const Tree &t);
    int eval() { return p->eval(); }
private:
    friend class Node;
    friend ostream& operator<<(ostream &os, const Tree &t);
    Node *p; // polymorphic hierarchy
};

void Tree::operator=(const Tree &t)
{
    ++t.p->use;
    if (--p->use == 0) 
        delete p;
    p = t.p;
}

ostream& operator<<(ostream &os, const Tree &t)
{
    t.p->print(os);
    return os;
}

class LeafNode: public Node {
private:
    friend class Tree;
    void print(ostream &os) = 0;
    virtual int eval() = 0;
};

class IntNode: public LeafNode {
public:
    int eval() { return n; }
private:
    friend class Tree;
    int n;
    void print(ostream &os) { os << n ;}
    IntNode(int k): n(k) { }
};

class IdNode: public LeafNode {
public:
    int eval() { return valtab[name]; }
private:
    friend class Tree;
    char name;
    void print(ostream& o) { o << name; }
    IdNode(char id): name(id) { }
};

class UnaryNode: public Node {
public:
    int eval();
private:
    friend class Tree;
    const char op;
    Tree opnd;
    UnaryNode(char a, Tree b): op(a), opnd(b) { }
    void print(ostream& o) { o << "(" << op << opnd << ")"; }
};

int UnaryNode::eval()
{
    switch (op) {
        case '-': return (-opnd.eval());
        case '+': return (+opnd.eval());
        default: cerr << "no operand" << endl;
            return 0;
    }
}

class BinaryNode: public Node {
public:
    int eval();
private:
    friend class Tree;
    const char op;
    Tree left;
    Tree right;
    BinaryNode(char a, Tree b, Tree c): op(a), left(b), right(c) { }
    void print(ostream &os) { os << "(" << left << op << right << ")"; }
};

int BinaryNode::eval()
{
    switch (op) {
        case '-': {
            future<int> left = async(launch::async, left.eval());
            future<int> right = async(launch::async, right.eval());
            //return (left.get() - right.get());
            }
        case '+': return (left.eval() + right.eval());
        case '*': return (left.eval() * right.eval());
        default: cerr << "no operand" << endl;
            return 0;
    }
}

Tree::Tree(int n) { p = new IntNode(n); }
Tree::Tree(char id) { p = new IdNode(id); }
Tree::Tree(char op, Tree t) { p = new UnaryNode(op, t); }
Tree::Tree(char op, Tree left, Tree right) { p = new BinaryNode(op, left, right); }

int main()
{   
    valtab['A'] = 3; valtab['B'] = 4;
    cout << "A = 3, B = 4" << endl;
    Tree t1 = Tree('*', Tree('-', 5), Tree('+', 'A', 4));
    Tree t2 = Tree('+', Tree('-', 'A', 1), Tree('+', t1, 'B'));
    cout << "t1 = " << t1 << ", t2 = " << t2 << endl;
    cout << "t1 = " << t1.eval() << ", t2 = " << t2.eval() << endl;

    return 0;
}

我收到此错误:

error: 'class std::future<int>' has no member named 'eval'

我想更改程序,以便以并行方式评估表达式。但是我坚持未来的实施,我不太明白它是如何运作的。好吧,我理解它是如何工作的,但我不明白为什么我会收到这些错误。

我希望有人可以给我一些提示或指出我正确的方向。

2 个答案:

答案 0 :(得分:1)

您尝试将虚拟成员函数作为异步调用,但未正确提供对象以将其固定。此外,您使用相同ID的本地变量而不直接引入错误会使难以置信难以阅读。

我相信这就是你拍摄的内容:

auto eLeft = std::async(std::launch::async, std::bind(&Tree::eval, &this->left));
auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (eLeft.get() - eRight.get());

虽然,说实话,这似乎有点矫枉过正。我认为将两个 asyncs旋转起来然后等待两个是没有意义的。为什么不旋转一个,然后使用当前线程执行任务的另一半:

auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (left.eval() - eRight.get());

答案 1 :(得分:1)

std::async的参数是一个函数(或更确切地说,是Callable)。

特别是,您不自行调用该函数(这将产生返回值)。调用由std::async完成。

所以这些行:

future<int> left = async(launch::async, left.eval());
future<int> right = async(launch::async, right.eval());

应改为阅读:

 future<int> left_result = std::async(launch::async, [this]() { return left.eval(); });
 future<int> right_result = std::async(launch::async, [this]() { return right.eval(); });

请注意,函数调用现在包装在lambda中。另请注意,您还在原始代码中重复使用leftright的名称,这更麻烦。我在这里将它们重命名为使它成功。

像往常一样,由于您现在在程序中具有并发性,因此您需要关心数据竞争。目前这似乎很好,因为树中的所有节点都是不同的,因此异步调用不会相互共享任何数据。但请记住以后的任何变化。