按照上图的时序,最终得到的x为11,但这显然是错误的,正确的x应该为12。这就体现了原子操作的必要性。
解释一下上面几个原语:
__sync_fetch_and_add(type *ptr, type value);
函数的返回值是 *ptr(旧值),同时 *ptr=*ptr+value
__sync_val_compare_and_swap(type *ptr, type oldval, type newval);
如果 *ptr不等于oldval,那么直接函数返回 *ptr,结束;
如果 *ptr等于oldval,那么函数返回 *ptr(旧值),同时 *ptr=newval
__sync_lock_test_and_set(type *ptr, type value);
函数的返回值是 *ptr(旧值),同时 *ptr=value
Types.h源码
#ifndef MUDUO_BASE_TYPES_H
#define MUDUO_BASE_TYPES_H
#include <stdint.h>
#include <string.h> // memset
#include <string>
#ifndef NDEBUG
#include <assert.h>
#endif
namespace muduo
{
using std::string;
inline void memZero(void* p, size_t n)
{
memset(p, 0, n);
}
template<typename To, typename From>
inline To implicit_cast(From const &f)
{
return f;
}
template<typename To, typename From> // use like this: down_cast<T*>(foo);
inline To down_cast(From* f)
{
#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
#endif
return static_cast<To>(f);
}
} // namespace muduo
#endif // MUDUO_BASE_TYPES_H
针对Types.h,我写了个测试小例子,顺便复习下RTTI:
我觉得这个例子挺好的^^
#include <iostream>
#include "muduo/base/Types.h"
using namespace std;
class B {
public:
virtual void foo(){}
};
class D :public B {
};
int main() {
B b_obj;
D d_obj;
B*pb = &b_obj;
D*pd = &d_obj;
//相比于普通的隐式转换pb=pd;把隐式转换封装成下面这种函数的形式,程序员阅读起来更明显
pb =muduo:: implicit_cast<B*, D*>(pd);
B*pb1 = &b_obj;//基类指针指向基类对象
B*pb2 = &d_obj;//基类指针指向派生类对象
D*pd1 = dynamic_cast<D*>(pb1);
if (pd1 == NULL)
{
cout <<"下行转换失败" << endl;
}
pd1 =muduo:: down_cast<D*>(pb3);//ok
return 0;
}
linux下结果:
gcc原子操作
Atomic.h
#ifndef MUDUO_BASE_ATOMIC_H
#define MUDUO_BASE_ATOMIC_H
#include "muduo/base/noncopyable.h"
#include <stdint.h>
namespace muduo
{
namespace detail
{
template<typename T>
class AtomicIntegerT : noncopyable
{
public:
AtomicIntegerT()
: value_(0)
{
}
T get()
{
return __sync_val_compare_and_swap(&value_, 0, 0);
}
T getAndAdd(T x)
{
return __sync_fetch_and_add(&value_, x);
}
T addAndGet(T x)
{
return getAndAdd(x) + x;
}
T incrementAndGet()
{
return addAndGet(1);
}
T decrementAndGet()
{
return addAndGet(-1);
}
void add(T x)
{
getAndAdd(x);
}
void increment()
{
incrementAndGet();
}
void decrement()
{
decrementAndGet();
}
T getAndSet(T newValue)
{
return __sync_lock_test_and_set(&value_, newValue);
}
private:
volatile T value_;
};
}
typedef detail::AtomicIntegerT<int32_t> AtomicInt32;//方便创建对象
typedef detail::AtomicIntegerT<int64_t> AtomicInt64;
} // namespace muduo
#endif // MUDUO_BASE_ATOMIC_H
测试代码:
Atomic_unittest.cc
#include "muduo/base/Atomic.h"
#include <assert.h>
int main()
{
{
muduo::AtomicInt64 a0;
assert(a0.get() == 0);
assert(a0.getAndAdd(1) == 0);//函数名字面意思很好理解,先get再add,后面类似
assert(a0.get() == 1);
assert(a0.addAndGet(2) == 3);
assert(a0.get() == 3);
assert(a0.incrementAndGet() == 4);//先+1再get
assert(a0.get() == 4);
a0.increment();
assert(a0.get() == 5);
assert(a0.addAndGet(-3) == 2);
assert(a0.getAndSet(100) == 2);//先get旧值再set新值
assert(a0.get() == 100);
}
{
muduo::AtomicInt32 a1;
assert(a1.get() == 0);
assert(a1.getAndAdd(1) == 0);
assert(a1.get() == 1);
assert(a1.addAndGet(2) == 3);
assert(a1.get() == 3);
assert(a1.incrementAndGet() == 4);
assert(a1.get() == 4);
a1.increment();
assert(a1.get() == 5);
assert(a1.addAndGet(-3) == 2);
assert(a1.getAndSet(100) == 2);
assert(a1.get() == 100);
}
}
没有任何输出说明测试结果没问题。