C++原子类实现

Wesley13
• 阅读 645

引言

在系统实现的过程中,经常需要用到计数功能,为了多线程下的安全使用,我自己定义了一个原子类。

基于Mutex的实现

我基于Mutex实现了一个简单的原子类,代码如下

/*
 * 说明:自定义整数操作的原子类,减少代码中的各种锁
 */

#ifndef _ATOMIC_INT64_H_
#define _ATOMIC_INT64_H_


#include <stdint.h>
#include "mutex.h"



template<class T>
class AtomicInt
{
public:
     AtomicInt(T value_) : value(value_){};

     //自增长操作,返回增长前的值
     void Increment(const T& step)
     {
         MutexGuard guard(mutex);
         value += step;
     }


     T GetValue()
     {
         MutexGuard guard(mutex);
         return value;
     }


 private:
     T value;
     Mutex mutex;
 };

 #endif

如代码所示,这是一种最简单的原子类实现方式,基于系统提供的互斥量,实现对变量的互斥访问。

C++11下的原子锁

C++11本身提供了原子锁供我们使用,非常方便,我写代码测试了一下,确实有效。 测试代码采用多线程分别对atomic int类型和普通的整数类型进行自增操作。结果发现 atomic int结果正确,而普通int类型数据不正确。

atomic_int32_t  atomicintparam = 0;
int32_t intparam = 0;
void thread_atomic_test()
{
    for (int i = 0; i < 10000; i++)
    {
        atomicintparam++;
        intparam++;
    }
}

void AtomicParamTest()
{
    vector<thread*> threads;
    for (int i = 0; i < 10; i++)
    {
        std::thread* task = new std::thread(thread_atomic_test);
        threads.push_back(task);
    }

    for (thread* task : threads)
    {
        task->join();
    }

    cout << "atomic int param: " << atomicintparam << endl;
    cout << "common int param: " << intparam << endl;
}

结果如下:

atomic int param: 100000
common int param: 86996

目前的情况是我们的编译器不支持C++11, 但是我觉得基于Mutex实现一个原子锁又过重。为了解惑,我做了一个测试,在10个线程的并发下对某个整数进行自增操作,加到1亿。测试下来的时间如下,单位毫秒:

atomic int param: 100000000(自增次数)     2969 (时间)
atomic int param: 100000000(自增次数)     13187(时间)

测试结果发现相差4倍左右,单线程加到1千万需要13s,我的场景里每个计数器计数不超过100,用mutex,还没有成为我的瓶颈,可以使用。

点赞
收藏
评论区
推荐文章
灯灯灯灯 灯灯灯灯
3年前
Java并发之ReentrantLock源码解析
Java并发之ReentrantLock源码解析Condition在上一章中,我们大概了解了Condition的使用,下面我们来看看Condition再juc的实现。juc下Condition本质上是一个接口,它只定义了这个接口的使用方式,具体的实现其实是交由子类完成。cpublicinterfaceConditionvoidawait()
Wesley13 Wesley13
3年前
java中多态的实现机制
多态的概念:  简单来说就是事物在运行过程中存在的不同状态,即父类或接口定义的引用变量指向子类或具体实现类的实例对象。程序调用方法在运行期才进行动态绑定,而不是引用变量的类型中定义的方法。多态存在的前提:1、存在继承关系,子类继承父类;2、子类重写父类的方法;3、父类引用指向子类对象。具体实例:1、定义一个父类:Animal
红橙Darren 红橙Darren
3年前
Android模板设计模式之 - 构建整个应用的BaseActivity
1\.模式介绍模式的定义定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。所有分享大纲:视频讲解地址:模式的使用场景1.多个子类有公有的方法,并且逻辑基本相同时。2.重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。3.重构时,模板方法模式
九章 九章
3年前
Android-自定义view
要自定义view,都知道有3个方法需要重写:onMeasure、onLayout、onDraw。而且这三个方法的执行是按顺序的。生命周期image.png实际开发中,比较多的自定义都是具体实现一个view的子类,实现viewgroup的子类比较少,两者基本相似,区别就是view需要实现onMeasure、onLayout、onDraw三个方法,而vie
Wesley13 Wesley13
3年前
CGLIB介绍与原理(通过继承的动态代理)
一、什么是CGLIB?CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。二、CGLIB原理CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的
Wesley13 Wesley13
3年前
Java多线程基础
(1)传统使用类Thread和接口Runnable实现 1\.在Thread子类覆盖的run方法中编写运行代码方式一 newThread(){@Overridepublicvoidrun(){while(true){try{Thread.sleep(2
Easter79 Easter79
3年前
Spring的Aop调用当前类的两种方法
我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?基于上面的思路有两种解决办法方法一:直接从
Stella981 Stella981
3年前
Python3中的super()函数详解
关于Python3中的super()函数我们都知道,在Python3中子类在继承父类的时候,当子类中的方法与父类中的方法重名时,子类中的方法会覆盖父类中的方法,那么,如果我们想实现同时调用父类和子类中的同名方法,就需要使用到super()这个函数,用法为super().函数名()下面是一个例子:
Wesley13 Wesley13
3年前
Java的类继承
知识点1、继承作用:提高代码的重用性,继承之后子类可以继承父类中的属性和方法减少重复代码条件:子类和父类要满足isa的逻辑关系,才能使用继承。如:苹果isa水果语法:使用extends连接子类和父类。子类extends父类Java是单继承,一个类只能继承一个父类。子类不能继承父类私有的属性,但是可以
Stella981 Stella981
3年前
Go 用 interface 模拟多态
多态是C这种语言中的概念,是指对不同的子类对象运行自己定义的方法。在Go语言中没有类的概念,但仍然可以使用structinterface来模拟实现类的功能。下面这个例子演示如何使用Go来模拟C中的多态行为。packagemainimport"fmt"//首先定义了一