Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Architectural patterns part 3
1. Architectural Patterns
[PART 3]
(Synchronization idioms & Pattern)
based on
Pattern-Oriented Software Architecture, Patterns for Concurrent and
Networked Objects, Volume 2
by Douglas Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann
2. Scoped Locking
It ensures that a lock is acquired automatically when control enters a scope and released
automatically when control leaves the scope.
Implementation 1. Define a guard class that acquires and releases a lock in its constructor and destructor
respectively.
class Thread_Mutex_Guard {
private:
Thread_Mutex *lock_; // Pointer to lock.
bool owner_; // Set to true when a lock is acquired
Thread_Mutex_Guard (const Thread_Mutex_Guard&);
// //disallow copy constructor and = operator
void operator= (const Thread_Mutex_Guard &);
public:
Thread_Mutex_Guard (Thread_Mutex &lock): lock_ (&lock), owner_ (false) {
lock_->acquire (); owner_ = true; }
~Thread_Mutex_Guard () { if (owner_) lock_->release (); }
};
3. Scoped Locking
2. call the thread_Mutex_Guard class object inside the class / function
Class test {
int test1(int index) {
Thread_Mutex_Guard guard (lock_);
if (/* condition */) {
// Do some more work ...
return true; } // End of scope releases the lock.
Return false ; // End of scope releases the lock.
}
Private :
Thread_Mutex lock_;
};
Mutex Lock is acquired and released automatically as control enters and leaves the test1()
method respectively.
Two specific functions acquire() and release() can be created inside the
Thread_Mutex_Guard class to acquire the lock and release the lock. In acquire(), it should
be verified if lock is already acquired. In release() should be verified if lock is already
released. This way if lock is already released , then release() in destructor can verify it.
4. Strategized Locking
The Strategized Locking technique parameterizes synchronization
mechanisms that protect a component's critical sections from concurrent
access.
To increase performance on large-scale multi-processor platforms, it may be
required to change the synchronization strategy to more efficient e.g. from
thread mutex to readers/writer lock which is time-consuming and error
prone.
Strategized Locking, the family of locking mechanisms becomes more
reusable and easier to apply across applications.
Implementation 1. Define an abstract interface for the locking mechanisms
2. Define a guard class and pass specific concrete lock object based on
requirement.
3. Update the component interface and implementation
5. Strategized Locking
# Define an abstract interface for the locking mechanisms
class Lock {
public:
// define methods.
virtual void acquire () = 0;
virtual void release () = 0;
};
# Define concrete classes for each kind of lock (e.g. concrete class for mutex lock)
class Thread_Mutex_Lock : public Lock {
public:
Virtual void acquire () { lock_.acquire (); }
Virtual void release () { lock_.release (); }
private:
Thread_Mutex mutexLock_; // Concrete lock type.
friend class Guard; // Define <test> as a friend so it can access <mutexLock_>
};
6. Strategized Locking
# Define guard class
class Guard {
public:
Guard (Thread_Mutex &lock): lock_ (&lock), owner_ (false) { lock_->acquire
(); owner_ = true; }
~Guard () { if (owner_) lock_->release (); }
private:
// Pointer to the lock.
Thread_Mutex *lock_;
bool owner_;
};
7. Strategized Locking
# Implement the interface
Polymorphic lock can be passed to the component either as a parameter in its
constructor or by adding a lock template parameter to the component declaration.
class test 1{
public:
// pass the Constructor the concrete lock object
test (Lock & mutexLock_) : lock_ (mutexLock_) {}; // lock passed as a parameter in its
constructor
void Function1(const char *pathname) {
Guard guard (lock_);
//Critical section
return;
}
private:
Thread_Mutex *lock_;
};
8. Thread-Safe Interface
This pattern ensures If a method that uses the Scoped Locking idiom, does
not call itself recursively to avoid self-deadlock.
Double-Checked Locking Optimization This technique avoids race conditions when accessing and modifying shared
resources by concurrent application during program execution
Implementation –
• All interface methods, (e.g. C++ public methods) should only
acquire/release component lock(s).
•
Implementation methods should only perform the task when called by interface
methods.
Example –
Thread safe single ton class Implementation with Double-Checked Locking technique.