提问者:小点点

如何正确使用unique_ptr进行多线程中的多态性? [已关闭]


类A是基本类,B是A的继承类,q是unique_ptr(class A)类型的队列。 下面是我的代码:

class A{
public:
    virtual void doSomeWork(){
        std::cout<< "doSomeBasicWork"<<std::endl;
    }
};

class B:public A{
public:
    void doSomeWork(){
        std::cout<< "doSomeSpecificWork"<<std::endl;
    }
};

int main(){
    std::unique_ptr<A> p=std::make_unique<B>();
    std::queue<std::unique_ptr<A>> q;
    q.push(std::move(p));
    auto x=std::move(q.front());
    x->doSomeWork();//print “doSomeSpecificWork”
}

所以你可以看到,在单线程中一切都很好,但是当我在多线程下重写这个:

#include <stdio.h>
#include <time.h>
#include <iomanip>
#include <windows.h>
#include<thread>
#include <iostream>
#include <queue>


class A{
public:
    virtual void doSomeWork(){
        std::cout<< "doSomeBasicWork"<<std::endl;
    }
};

class B:public A{
public:
    void doSomeWork(){
        std::cout<< "doSomeSpecificWork"<<std::endl;
    }
};

void producer(std::queue<std::unique_ptr<A>>& q){
        Sleep(1000);
        auto a=std::make_unique<A>();
        q.push(std::move(a));
}

void consumer(std::queue<std::unique_ptr<A>>& q){
        Sleep(1500);
        auto p=std::move(q.front());
        q.pop();
        p->doSomeWork();
}


int main(){
    auto q=std::queue<std::unique_ptr<A>>();
    auto t1=std::thread(consumer,std::ref(q));
    auto t2=std::thread(producer,std::ref(q));
    t1.join();
    t2.join();
}

输出将是“DoSomeBasicWork”,多态性消失了。 我该怎么做才能解决这个问题?


共1个答案

匿名用户

正如所指出的,根本原因是一个打字错误。 但是,我强烈怀疑输出会是一样的。 这是因为您使用了std::make_unique。 这将创建一个新实例,但其基类型为a。 你可以在这里读到这一点,重要的部分是:

构造类型T的对象并将其包装在std::unique_ptr中。

为了解决这个问题,您必须模板化您的函数,向std::make_unique提供具体类型

像这样的东西:

template<class TType>
void producer(std::queue<std::unique_ptr<A>>& q){
        Sleep(1000);
        auto a=std::make_unique<TType>();
        q.push(std::move(a));
}

而且,正如其他人所指出的,你需要使用某种锁定机制,否则你会得到竞态条件。 看看这里和这里。