• c++经验之谈一:RAII原理介绍


    1.什么是RAII

    RAII(Resource Acquisition Is Initialization)是由c++之父Bjarne Stroustrup提出的,中文翻译为资源获取即初始化,他说:使用局部对象来管理资源的技术称为资源获取即初始化;这里的资源主要是指操作系统中有限的东西如内存、网络套接字等等,局部对象是指存储在栈的对象,它的生命周期是由操作系统来管理的,无需人工介入;

    2.RAII的原理

    资源的使用一般经历三个步骤a.获取资源 b.使用资源 c.销毁资源,但是资源的销毁往往是程序员经常忘记的一个环节,所以程序界就想如何在程序员中让资源自动销毁呢?c++之父给出了解决问题的方案:RAII,它充分的利用了C++语言局部对象自动销毁的特性来控制资源的生命周期。给一个简单的例子来看下局部对象的自动销毁的特性:

    #include <iostream>
    using namespace std;
    class person {
      public:
          person(const std::string name = "", int age = 0) : 
          name_(name), age_(age) {
                std::cout << "Init a person!" << std::endl;
          }
          ~person() {
                std::cout << "Destory a person!" << std::endl;
          }
          const std::string& getname() const {
                return this->name_;
          }    
          int getage() const {
                return this->age_;
          }      
      private:
          const std::string name_;
          int age_;  
    };
    int main() {
        person p;
        return 0;
    }
    编译并运行:
    g++ person.cpp -o person
    ./person 
    运行结果:
    Init a person!
    Destory a person!
    

    从person class可以看出,当我们在main函数中声明一个局部对象的时候,会自动调用构造函数进行对象的初始化,当整个main函数执行完成后,自动调用析构函数来销毁对象,整个过程无需人工介入,由操作系统自动完成;于是,很自然联想到,当我们在使用资源的时候,在构造函数中进行初始化,在析构函数中进行销毁。整个RAII过程我总结四个步骤:

    a.设计一个类封装资源

    b.在构造函数中初始化

    c.在析构函数中执行销毁操作

    d.使用时声明一个该对象的类

    3.RAII的应用

    本节主要通过一个简单的例子来说明如何将RAII应用到我们的代码中。linux下经常会使用多线程技术,说到多线程,就得提到互斥锁,互斥锁主要用于互斥,互斥是一种竞争关系,用来保护临界资源一次只被一个线程访问,按照我们前面的分析,我们封装一下POSIX标准的互斥锁:

    #include <pthread.h>
    #include <cstdlib>
    #include <stdio.h>
    
    class Mutex {
     public:
      Mutex();
      ~Mutex();
    
      void Lock();
      void Unlock(); 
    
     private:
      pthread_mutex_t mu_;
    
      // No copying
      Mutex(const Mutex&);
      void operator=(const Mutex&);
    };
    
    
    #include "mutex.h"
    
    static void PthreadCall(const char* label, int result) {
      if (result != 0) {
        fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
      }
    }
    
    Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); }
    
    Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); }
    
    void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); }
    
    void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); }

    写到这里其实就可以使用Mutex来锁定临界区,但我们发现Mutex只是用来对锁的初始化和销毁,我们还得在代码中调用Lock和Unlock函数,这又是一个对立操作,所以我们可以继续使用RAII进行封装,代码如下:

    #include "mutex.h"
    
    class  MutexLock {
     public:
      explicit MutexLock(Mutex *mu)
          : mu_(mu)  {
        this->mu_->Lock();
      }
      ~MutexLock() { this->mu_->Unlock(); }
    
     private:
      Mutex *const mu_;
      // No copying allowed
      MutexLock(const MutexLock&);
      void operator=(const MutexLock&);
    };

    到这里我们就真正封装了互斥锁,下面我们来通过一个简单的例子来使用它,代码如下:

    #include "mutexlock.hpp"
    #include <unistd.h>
    #include <iostream>
    
    #define    NUM_THREADS     10000
    
    int num=0;
    Mutex mutex;
    
    void *count(void *args) {
        MutexLock lock(&mutex);
        num++;
    }
    
    
    int main() {
        int t;
        pthread_t thread[NUM_THREADS];
    
        for( t = 0; t < NUM_THREADS; t++) {   
            int ret = pthread_create(&thread[t], NULL, count, NULL);
            if(ret) {   
                return -1;
            }   
        }
    
        for( t = 0; t < NUM_THREADS; t++)
            pthread_join(thread[t], NULL);
        std::cout << num << std::endl;
        return 0;
    }
    
    编译并运行:g++ test_mutexlock.cpp mutexlock.hpp mutex.cpp mutex.h -o test_mutexlock -lpthread
    ./test_mutexlock 
    运行结果:10000  符合预期(可以去掉MutexLock lock(&mutex);试试看看结果如何?)



    https://github.com/vichargrave/mutex/blob/master/Makefile


  • 相关阅读:
    sass中使用穿透属性(deep)修改第三方组件样似
    Codeforces Round #647 (Div. 2) D. Johnny and Contribution(BFS)
    Codeforces Round #647 (Div. 2) C. Johnny and Another Rating Drop(数学)
    Codeforces Round #647 (Div. 2) B. Johnny and His Hobbies(枚举)
    Codeforces Round #647 (Div. 2) A. Johnny and Ancient Computer
    AtCoder Beginner Contest 169
    Codeforces Round #646 (Div. 2) E. Tree Shuffling(树上dp)
    Codeforces Round #646 (Div. 2) C. Game On Leaves(树上博弈)
    Codeforces Round #646 (Div. 2) B. Subsequence Hate(前缀和)
    Codeforces Round #646 (Div. 2) A. Odd Selection(数学)
  • 原文地址:https://www.cnblogs.com/xiaochouk/p/16343996.html
Copyright © 2020-2023  润新知