【发布时间】:2020-10-21 23:59:08
【问题描述】:
A类是基本类,B是A的继承类,q是unique_ptr(class A)类型的队列。我想从q中获取元素,并为那些继承类调用特殊函数。 这是我的代码:
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" ,多态性消失了。 我应该怎么做才能解决这个问题?
【问题讨论】:
-
对于线程,您使用
std::make_unique<A>(),而在第一种情况下使用std::make_unique<B>()。投票关闭为错字。另请注意,std::queue不是线程安全的。您不能在没有同步的情况下在多个线程中使用它。Sleep()不提供。 -
你有一个数据竞争,所以你的程序的行为是未定义的。您需要同步对队列的访问,例如通过锁定
std::mutex -
make_unique<A>总是构造一个A。如果要将指向B的指针存储在unique_ptr<B>中,则需要明确指定该变量是unique_ptr<B>,而不是auto(然后您可以根据喜好以几种不同的方式构造它)。但是有人可能会问,如果容器中仅包含unique_ptr<B>,那么为什么不直接在容器中使用,此时需要更多上下文。 -
旁白:你可以
q.push(std::make_unique<B>());
标签: c++ multithreading unique-ptr