C++技巧(多线程下的返回值优化陷阱)

C++技巧(多线程下的返回值优化陷阱),第1张

C++技巧(多线程下的返回值优化陷阱),第2张

“函数返回值优化”是我们程序常用的优化方法。只要有可能,我们应该返回对对象的有效引用,而不是重新生成一个临时对象。然而,也许这个想法需要在多线程中更仔细地考虑。
exmoda从一个简单的例子开始:
Template
ClassFDMAP
{
STD::vector vec _;
public:
void Set(int FD,const T & v){
if(FD > = 0){
if(FD < vec _。size()){
vec _[FD]= v;
}else{
vec_。调整大小(FD+1);
vec _[FD]= v;
}
}
}
T Get(int FD)const {
if(FD > = 0 & & FD < vec _。size())
return vec _[FD];
return T();
}
};
这里FdMap是将int映射到T对象的类型,std::vector在考试中作为底层容器。它做的事情很简单:在需要的时候展开容器vec \如果访问超出范围,则返回t的默认值。
如果FdMap要在多线程下工作,考试大,那么我们就需要添加一点代码进行必要的同步:
Template
Class FD map
{
STD::Vector VEC _;
Mutex Mutex _;//锁定同步对象
public:
void set(int FD,const t & v){
if(FD > = 0){
guard g(mutex _)//锁定
if(FD
} else {
vec _。调整大小(FD+1);
vec _[FD]= v;
}
}
}
tget(int FD)const {
if(FD > = 0){
guard g(mutex _)//lock

}
return T();
}
};
其中Mutex是任何线程同步类型;Guard是对应的作用域守卫类型,在构造时锁定mutex_在析构时解锁。到目前为止,FdMap类是完美的,没有任何问题。
在实际应用中,我们可能会使用FdMap将socket fd与对应的客户端连接对象(比如ClientData)关联起来,那么可能的实例化就是FdMap。
但是,有经验的程序员会马上看出,直接在FdMap中存储ClientData指针是不可能的。如果一个线程获得了一个fd的ClientData指针,但是另一个线程试图关闭fd连接,ClientData对象会被释放还是保持有效?如果ClientData对象被释放,前一个线程的后续访问将无效;如果保留ClientData对象,那么没有人知道什么时候释放它,内存就会泄漏。
正确的做法是将ClientData的智能指针存储在FdMap中,所以不需要任何线程专门释放ClientData对象,智能指针会适时处理。为了保险,我们决定用boost::shared_ptr,因为大家都觉得它是正确的。
好了,我们有了一个设计完美、运行正确的FdMap。完整的实例化是:
FdMap
终于有一天,我们需要优化代码,于是我们重新审视上面的代码。获取功能!是的,它的返回值可以优化吗?对于智能指针来说,即使复制构造函数也是很昂贵的,减少一个临时对象的构造对我们来说确实很有诱惑力。
但是有一个很明显的问题:当fd超出范围时,返回谁的引用?看看下面的实现。
这里是我们的“优化”:
const t & get(intfd)const {
static const t t def = t();
if(FD > = 0){
guard g(mutex _)//lock
if(FD < vec _。size()){
return vec _[FD];
}
return DEF;
}
通过增加一个局部静态常量def解决了返回默认引用的问题。如果fd在范围内,返回vec_中的对象引用是没有问题的。
但是当我再次运行这个“优化版”时,不幸的是,程序在一天后崩溃了!这是怎么回事?我查了所有使用Get函数的地方:
boost::shared _ ptrpclient = FD map . Get(FD);
这样的代码没有任何问题,而且当你检查Get函数的实现时,也没有发现任何问题!
其实问题是这样的:
仔细分析Get函数的操作可以发现,在“return vec _[FD];”之后FdMap内部的锁已经被解锁,此时调用线程仍然得到FdMap::vec_[fd]对象的引用,所以下一次给pClient赋值就是一个没有任何保护的进程。如果FdMap::vec_[fd]在将这个引用赋给pClient的过程中,没有被任何其他线程更改,那么一切正常;否则,程序可能会崩溃!
知道了这个例子,相信你在以后的优化过程中,处理多线程下的代码会更加谨慎。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++技巧(多线程下的返回值优化陷阱)

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情