in C/C++, Linux

Resource Acquisition Is Initialization( RAII )

Resource Acquisition Is Initialization is a terminology which describe that the resource will be guaranteed to be freed or released when the object is out of the scope.

For example, in the following code:
Suppose we use the a mutex to control some resource so that the resource can be used by other object only when the mutex is unlocked.

class Mutex{
private:
 bool Locked;
public:
 Mutex(){}

 void lock(){
  Locked = true;
  cout << "The Mutex is locked!" << endl;
 }

 void unlock(){
  Locked = false;
  cout << "The Mutex is unlocked!" << endl;
 }

 ~Mutex(){}
};

But if there is some exception occurs during the operation, the mutex.unlock() function will never be executed.That is to say the lock will be never be released.

void main(){
 Mutex mutex;

 try{
  mutex.lock(); // lock the mutex before we do some operation

  throw "Exception occurs"; //we assume there is an
                            //exception occurs during
                            //the operation.

  mutex.unlock(); // unlock the mutex after the operation.
                  // this function will not be called
                  // in this situation.
 }
 catch(char* error){
  cout << error << endl;
 }
}

And the output is :

The Mutex is locked!
Exception occurs

Now let us use the RAII technique to solve this problem:

First,let us define a template scope_resource class. When the scope_resource is out of scope, the scope_resource will do the operation defined in the ReleasePolicy class to release the T.

Code for the scope_resource template class:

template class scoped_resource{

private:
 T resource;
 typedef T resource_type;
 typedef ReleasePolicy release_type;

public:
 //prohibited operations
 scoped_resource(const scoped_resource&);
 scoped_resource& operator = (const scoped_resource&);

 scoped_resource(resource_type res = resource_type() ):resource(res){}

 resource_type getResource(){
  return resource;
 }
 /** main operation for releasing the resource */
 ~scoped_resource(){
  release_type()(resource);
 }
};

Then we define the releasePolicy struct/class:

struct release_lock{
 /** () operator for releasing the mutex */
 void operator() (Mutex mutex) const{
 mutex.unlock();
 }
};

And in the main function:

void main(){
 typedef scoped_resource scoped_mutex;
 scoped_mutex mutex;

 try{
 mutex.getResource().lock(); // lock the mutex before
                             // we do some operation.

 throw "Exception occurs"; //we assume there is an
                           //exception occurs during
                           //the operation.

                           //do not need unlock function.
                           //scoped_mutex will release the mutex
                           //automatically
 }
 catch(char* error){
  cout << error << endl;
 }
}

Final output:

The Mutex is locked!
Exception occurs
The Mutex is unlocked!

Write a Comment

Comment