Tuesday, July 17, 2012

"Execute Around Sequence", C++ Pattern

For clearing the need for this pattern, I start this post with a problem statement.
Problem:
"suppose that we have a pair of actions that surrounds a sequence of  statements and we need abstract that actions around the statements and have a error prone and exception safe code".
Let's start with a sample code snippet :
void F()
{
  |----------------------------------------------------------------------------------------------------------|
  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
  
  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

  |---------------------------------------------------------------------------------------------------------|
   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|


}
    ---------------- Code 1 -----------------------
What happens in "Code 1" if an exception occur in block 2?. Answer is easy; block 3 won't run! So acquired lock will not be unlocked and other threads will waiting for unlock forever, allocated memory in part 1 won't be freed and all resources acquired in part1 won't be released.
Solution:
Initial solution which may bloom in your mind may be following strategy :

void F()
{
  |----------------------------------------------------------------------------------------------------------|

  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
   try

{
  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|
} catch(...)
{
  throw ;
}
finally
{
  |---------------------------------------------------------------------------------------------------------|

   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

}
}

    ---------------- Code 2-----------------------
But as you know, C++ doesn't have finally statement in exception handling. So we have to change the code as following :


void F()
{
  |----------------------------------------------------------------------------------------------------------|
  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
   try
{

  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

} catch(...)
{
  |---------------------------------------------------------------------------------------------------------|

   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

  throw ;
}

  |---------------------------------------------------------------------------------------------------------|
   |3'. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

}

    ---------------- Code 3-----------------------
Code 3 is an acceptable solution but how about the case you are not allowed to use try/catch ?
Considering this fact that destructor of C++ class will run automatically if object goes out of scope, guides us to write a class and put "block 1" of Code 1 into a constructor of class and "block 3" of Code 1 into destructor of that class. This way helps us to achieve an exception safe code which is named executive around sequence :

class scoped_resource_manager
{
public:
  scoped_resource_manager(resource_related_parameters)
{
     block 1 : acquires lock,allocate memory, open connections ....
}
~scoped_resource_manager()
{
     block 3 :  release lock, free memory , close  connection ...
}

}

void F()
{
 scoped_resource_manager resource_manager(resource_related_parameters);
  |----------------------------------------------------------------------------------------------------|

  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

}

    ---------------- Code 4-----------------------
In Code 4, we are not worry if exception occurs in block 2 or not; all allocated resources will be released  when function returns or execution steps out of it's scope because of automatically running  of scoped_resource_manager class destructor.!

Thanks for C++ class destructors.
"Finally" here is a simple real world code sample for you :
 class ScopedConnection
{
 private :
  BaseDBProvider *mDB;
 public:
  ScopedConnection(BaseDBProvider *pDB)
  {
   mDB=pDB;
   mDB->Open();
                       mDB->StartTransaction();
                }
  ~ScopedConnection()
  {
                        mDB->DetachTransaction();
                  mDB->Close();
  }
};
void F()
{
 BaseDBProvider *bdp=DBFactory::GetDBProvider();
 ScopedConnection scoped_con(bdp);
 DBDataReader *dr;
 dr=bdp->ExcecuteReader(dbs);
 while(dr->ReadNext())
  ret->push_back(Load(dr));
 return ret;
}

scoped_ptr<T> and scoped_lock ( from boost library ) are also implemented to help us in such problems.

No comments :

Post a Comment

Tuesday, July 17, 2012

"Execute Around Sequence", C++ Pattern

For clearing the need for this pattern, I start this post with a problem statement.
Problem:
"suppose that we have a pair of actions that surrounds a sequence of  statements and we need abstract that actions around the statements and have a error prone and exception safe code".
Let's start with a sample code snippet :
void F()
{
  |----------------------------------------------------------------------------------------------------------|
  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
  
  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

  |---------------------------------------------------------------------------------------------------------|
   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|


}
    ---------------- Code 1 -----------------------
What happens in "Code 1" if an exception occur in block 2?. Answer is easy; block 3 won't run! So acquired lock will not be unlocked and other threads will waiting for unlock forever, allocated memory in part 1 won't be freed and all resources acquired in part1 won't be released.
Solution:
Initial solution which may bloom in your mind may be following strategy :

void F()
{
  |----------------------------------------------------------------------------------------------------------|

  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
   try

{
  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|
} catch(...)
{
  throw ;
}
finally
{
  |---------------------------------------------------------------------------------------------------------|

   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

}
}

    ---------------- Code 2-----------------------
But as you know, C++ doesn't have finally statement in exception handling. So we have to change the code as following :


void F()
{
  |----------------------------------------------------------------------------------------------------------|
  |1. block of code which acquires lock, memory or other resources and some other statements |
  |----------------------------------------------------------------------------------------------------------|
   try
{

  |----------------------------------------------------------------------------------------------------|
  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

} catch(...)
{
  |---------------------------------------------------------------------------------------------------------|

   |3. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

  throw ;
}

  |---------------------------------------------------------------------------------------------------------|
   |3'. block of code which release lock, memory or other resources and some other statements |
  |---------------------------------------------------------------------------------------------------------|

}

    ---------------- Code 3-----------------------
Code 3 is an acceptable solution but how about the case you are not allowed to use try/catch ?
Considering this fact that destructor of C++ class will run automatically if object goes out of scope, guides us to write a class and put "block 1" of Code 1 into a constructor of class and "block 3" of Code 1 into destructor of that class. This way helps us to achieve an exception safe code which is named executive around sequence :

class scoped_resource_manager
{
public:
  scoped_resource_manager(resource_related_parameters)
{
     block 1 : acquires lock,allocate memory, open connections ....
}
~scoped_resource_manager()
{
     block 3 :  release lock, free memory , close  connection ...
}

}

void F()
{
 scoped_resource_manager resource_manager(resource_related_parameters);
  |----------------------------------------------------------------------------------------------------|

  |--2. ---- Sequences of statements                                                     |
  |----------------------------------------------------------------------------------------------------|

}

    ---------------- Code 4-----------------------
In Code 4, we are not worry if exception occurs in block 2 or not; all allocated resources will be released  when function returns or execution steps out of it's scope because of automatically running  of scoped_resource_manager class destructor.!

Thanks for C++ class destructors.
"Finally" here is a simple real world code sample for you :
 class ScopedConnection
{
 private :
  BaseDBProvider *mDB;
 public:
  ScopedConnection(BaseDBProvider *pDB)
  {
   mDB=pDB;
   mDB->Open();
                       mDB->StartTransaction();
                }
  ~ScopedConnection()
  {
                        mDB->DetachTransaction();
                  mDB->Close();
  }
};
void F()
{
 BaseDBProvider *bdp=DBFactory::GetDBProvider();
 ScopedConnection scoped_con(bdp);
 DBDataReader *dr;
 dr=bdp->ExcecuteReader(dbs);
 while(dr->ReadNext())
  ret->push_back(Load(dr));
 return ret;
}

scoped_ptr<T> and scoped_lock ( from boost library ) are also implemented to help us in such problems.

No comments :

Post a Comment