티스토리 뷰

싱글톤 패턴(Singleton Pattern)



 객체를 사용할 때 매번 생성하지 않고 딱 한 번의 생성을 통해 이를 재활용 하는 패턴입니다.

객체 생성 횟수를 줄여서 메모리를 절약가능하긴 하지만, 요즘과 같이 메모리가 넘쳐나는 시대에 크게 와닿지 않습니다. 


다른 이유는 없을까요? 다들 사무실에서 프린터를 사용해본 경험이 있을 것 입니다. 네트워크로 연결해서 여러사람들이 쓸 수 있게 연결되어 있습니다. 어떻게 사용되는지 자세하세 살펴 볼까요


사용자1


사용자2


사용자3   ----▷ TCP/IP   ----▷ 프린터(요청된 작업 한개를 출력)


  ...


사용자 N


프린터는 사용자1, 2, 3 으로부터 작업을 언제든지 받을 수 있습니다. 사용자1이 요청하자마자 사용자2 가 다른 작업을 요청하면 똑똑한 프린터는 작업큐 라는 공간을 만들어서 순차적으로 처리를 합니다. 그럼 이런 큐를 2개 이상이 생성한다면 다들 글자 한줄 짜리 프린트 물을 받아 볼지도 모릅니다. 보통은 시스템 자원관리, 정보 등을 관리하는 thread pool, work pool, connection pool 은 싱클톤패턴을 사용하고 있답니다.






#include <iostream> class singleton { // 포인터를 통해 딱 한개의 instance 를 관리 static singleton* _instance; singleton() {}; public: // c++11 style : copy constructor 호출 되지 못하도록 singleton(const singleton& other) = delete; // singleton 객체 생성 static singleton* get_instance() { if (_instance == nullptr) { _instance = new singleton(); } return _instance; } // singletone 객체 해제 static void release_instance() { if (_instance) { delete _instance; _instance = nullptr; } } }; // 기본 _instance 값을 nullptr 로 설정 singleton* singleton::_instance = nullptr; int main() { singleton* instance = singleton::get_instance(); instance->release_instance(); return 0; }





아 이제 완성이 되었네요. 정말로 이제 singleton 객체를 통해 pool 관리도 하고 멋진 일들을 해낼 수 있다고 믿는 순간, 한가지 의문이 생깁니다. 사용자1, 2가 동시에 생성해달라고 하면 어떤 일이 일어 날까요? singleton 객체가 2번이나 생성 될 수 있어 알지 못하게 memory leakage 가 발생해 버립니다. 몇 백번쯤이야 상관없지만 수십만번 된다고 하면 끔찍일이 생기겠네요.


 thread-safe singleton 을 한번 만들어보겠습니다. c++11 로 넘어오면서 많인 기능들이 생겼는데 그중 한개가 #include <mutex>에 들어있는 mutex 입니다. 이를 통해 손쉽게 thread 동기화가 가능합니다.







#include <mutex> class singleton { static singleton* _instance; // thread safe 보장하려면 mutex가 필요해 static std::mutex _mutex; singleton() {}; public: singleton(const singleton& other) = delete; static singleton* get_instance() { if (_instance == nullptr) { // lock 을 걸면 다른 thread는 기다려요 _mutex.lock(); _instance = new singleton(); _mutex.unlock(); // unlock 을 하면 이제 thread가 작업해요 } return _instance; } static void release_instance() { if (_instance) { delete _instance; _instance = nullptr; } } };


요즘 대부분은 lock, unlock 이 아닌 동일한 기능을 하는 std::lock_guard 를 사용하고 있습니다.
-- 참조 : http://en.cppreference.com/w/cpp/thread/lock_guard



간단히   thread 2개를 생성해서 singletone 객체를 생성하는 코드를 구성해 보겠습니다.





#include <iostream> #include <mutex> #include <thread> class singleton { static singleton* _instance; static std::mutex _mutex; singleton() {}; public: singleton(const singleton& other) = delete; static singleton* get_instance() { std::lock_guard<std::mutex> lock(_mutex); if (_instance == nullptr) { //_mutex.lock(); _instance = new singleton(); //_mutex.unlock() std::cout << "한번만 실행됩니다." << std::endl; } return _instance; } static void release_instance() { if (_instance) { delete _instance; _instance = nullptr; } } }; //http://en.cppreference.com/w/cpp/language/static 참조 std::mutex singleton::_mutex; singleton* singleton::_instance = nullptr; void make_instance_with_thread(singleton* ptr) { ptr = singleton::get_instance(); } int main() { singleton* instance; std::thread t1(make_instance_with_thread, instance); std::thread t2(make_instance_with_thread, instance); t1.join(); t2.join(); instance->release_instance(); return 0; }


'프로그래밍 > Design pattern(C++)' 카테고리의 다른 글

Visitor pattern (c++)  (0) 2017.05.07
Strategy pattern (c++)  (0) 2017.05.05
iterator (c++)  (0) 2017.04.24
Design Patterns  (0) 2017.04.23
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함