主要分析內(nèi)容:
bvar::Adder<int> test;
test << 1;
test.get_value();
1、operator<<
Adder定義:
template <typename T>
class Adder : public Reducer<T, detail::AddTo<T>, detail::MinusFrom<T> > {
public:
typedef Reducer<T, detail::AddTo<T>, detail::MinusFrom<T> > Base;
typedef T value_type;
typedef typename Base::sampler_type sampler_type;
public:
Adder() : Base() {}
explicit Adder(const butil::StringPiece& name) : Base() {
this->expose(name);
}
Adder(const butil::StringPiece& prefix,
const butil::StringPiece& name) : Base() {
this->expose_as(prefix, name);
}
~Adder() { Variable::hide(); }
};
operator<<:
定義在Reducer中。
template <typename T, typename Op, typename InvOp>
inline Reducer<T, Op, InvOp>& Reducer<T, Op, InvOp>::operator<<(
typename butil::add_cr_non_integral<T>::type value) {
// It's wait-free for most time
agent_type* agent = _combiner.get_or_create_tls_agent();
if (__builtin_expect(!agent, 0)) {
LOG(FATAL) << "Fail to create agent";
return *this;
}
agent->element.modify(_combiner.op(), value);
return *this;
}
Reducer中
typedef typename detail::AgentCombiner<T, T, Op> combiner_type;
...
combiner_type _combiner;
...
AgentCombiner構(gòu)造函數(shù):
AgentGroup::create_new_agent()保證了id的唯一蜡娶。
explicit AgentCombiner(const ResultTp result_identity = ResultTp(),
const ElementTp element_identity = ElementTp(),
const BinaryOp& op = BinaryOp())
: _id(AgentGroup::create_new_agent())
, _op(op)
, _global_result(result_identity)
, _result_identity(result_identity)
, _element_identity(element_identity) {
}
_combiner.get_or_create_tls_agent()
// We need this function to be as fast as possible.
inline Agent* get_or_create_tls_agent() {
Agent* agent = AgentGroup::get_tls_agent(_id);
if (!agent) {
// Create the agent
agent = AgentGroup::get_or_create_tls_agent(_id);
if (NULL == agent) {
LOG(FATAL) << "Fail to create agent";
return NULL;
}
}
if (agent->combiner) {
return agent;
}
agent->reset(_element_identity, this);
// TODO: Is uniqueness-checking necessary here?
{
butil::AutoLock guard(_lock);
_agents.Append(agent);
}
return agent;
}
2锅棕、get_value
// Get reduced value.
// Notice that this function walks through threads that ever add values
// into this reducer. You should avoid calling it frequently.
T get_value() const {
CHECK(!(butil::is_same<InvOp, detail::VoidOp>::value) || _sampler == NULL)
<< "You should not call Reducer<" << butil::class_name_str<T>()
<< ", " << butil::class_name_str<Op>() << ">::get_value() when a"
<< " Window<> is used because the operator does not have inverse.";
return _combiner.combine_agents();
}
combine_agents:
// [Threadsafe] May be called from anywhere
ResultTp combine_agents() const {
ElementTp tls_value;
butil::AutoLock guard(_lock);
ResultTp ret = _global_result;
for (butil::LinkNode<Agent>* node = _agents.head();
node != _agents.end(); node = node->next()) {
node->value()->element.load(&tls_value);
call_op_returning_void(_op, ret, tls_value);
}
return ret;
}