引言
在系统实现的过程中,经常需要用到计数功能,为了多线程下的安全使用,我自己定义了一个原子类。
基于Mutex的实现
我基于Mutex实现了一个简单的原子类,代码如下
1/* 2 * 说明:自定义整数操作的原子类,减少代码中的各种锁 3 */ 4 5#ifndef _ATOMIC_INT64_H_ 6#define _ATOMIC_INT64_H_ 7 8 9#include <stdint.h> 10#include "mutex.h" 11 12 13 14template<class T> 15class AtomicInt 16{ 17public: 18 AtomicInt(T value_) : value(value_){}; 19 20 //自增长操作,返回增长前的值 21 void Increment(const T& step) 22 { 23 MutexGuard guard(mutex); 24 value += step; 25 } 26 27 28 T GetValue() 29 { 30 MutexGuard guard(mutex); 31 return value; 32 } 33 34 35 private: 36 T value; 37 Mutex mutex; 38 }; 39 40 #endif
如代码所示,这是一种最简单的原子类实现方式,基于系统提供的互斥量,实现对变量的互斥访问。
C++11下的原子锁
C++11本身提供了原子锁供我们使用,非常方便,我写代码测试了一下,确实有效。 测试代码采用多线程分别对atomic int类型和普通的整数类型进行自增操作。结果发现 atomic int结果正确,而普通int类型数据不正确。
1atomic_int32_t atomicintparam = 0; 2int32_t intparam = 0; 3void thread_atomic_test() 4{ 5 for (int i = 0; i < 10000; i++) 6 { 7 atomicintparam++; 8 intparam++; 9 } 10} 11 12void AtomicParamTest() 13{ 14 vector<thread*> threads; 15 for (int i = 0; i < 10; i++) 16 { 17 std::thread* task = new std::thread(thread_atomic_test); 18 threads.push_back(task); 19 } 20 21 for (thread* task : threads) 22 { 23 task->join(); 24 } 25 26 cout << "atomic int param: " << atomicintparam << endl; 27 cout << "common int param: " << intparam << endl; 28}
结果如下:
1atomic int param: 100000 2common int param: 86996
目前的情况是我们的编译器不支持C++11, 但是我觉得基于Mutex实现一个原子锁又过重。为了解惑,我做了一个测试,在10个线程的并发下对某个整数进行自增操作,加到1亿。测试下来的时间如下,单位毫秒:
1atomic int param: 100000000(自增次数) 2969 (时间) 2atomic int param: 100000000(自增次数) 13187(时间)
测试结果发现相差4倍左右,单线程加到1千万需要13s,我的场景里每个计数器计数不超过100,用mutex,还没有成为我的瓶颈,可以使用。