With the introduction of exceptions, writing code has become increasingly complex. Any resource acquired has to be released when no longer in use. If not handled properly will lead to handle leaks, memory leaks and in some cases deadlocks which are very difficult to debug.
Guard classes takes advantage of the fact that the destructor is always called for an object on the stack regardless of how you exit from the function scope.
Key Idea
unsigned __stdcall func(void *args)
{
static Lock lock;
Guard guard(lock);
// operations
return 0;
}
#ifndef _Guard_H_ #define _Guard_H_ #include "Lock.h" namespace examples { class Guard { public: Guard(Lock &lock) : m_lock(lock) { m_lock.acquire(); } ~Guard() { m_lock.release(); } private: Guard(); Guard(const Guard&); Guard& operator=(const Guard&); Lock &m_lock; }; } #endif //_Guard_H_The program demonstrates the use of Guard class to acquire() and release() the lock
The Complete Code
#include <windows.h> #include <process.h> #include <iostream> #include <assert.h> #include "Lock.h" #include "Guard.h" using namespace examples; static bool alive = true; static int current = 0; unsigned __stdcall put(void *args) { static Lock lock; while(alive) { Guard guard(lock); current = current + 10; ::Sleep(500); std::cout << current << std::endl; } return 0; } int main() { // create threads unsigned t1; HANDLE h1 = (HANDLE) ::_beginthreadex(0, 0, &put, 0, CREATE_SUSPENDED, &t1); assert(h1 != 0); unsigned t2; HANDLE h2 = (HANDLE) ::_beginthreadex(0, 0, &put, 0, CREATE_SUSPENDED, &t2); assert(h2 != 0); // start threads ::ResumeThread(h1); ::ResumeThread(h2); ::Sleep(10000); alive = false; ::WaitForSingleObjectEx(h1, INFINITE, false); ::WaitForSingleObjectEx(h2, INFINITE, false); ::CloseHandle(h1); ::CloseHandle(h2); return 0; }
References:
Exception Safe Code
Thinking in C++ Practical Programming
No comments :
Post a Comment