This page is READ-ONLY. It is generated from the old site.
All timestamps are relative to 2013 (when this page is generated).
If you are looking for TeX support, please go to VietTUG.org

Singleton in multi-threading environment

how should we implement? (C++, Java)
Added by bronzeboyvn almost 3 years ago  »  Votes: 1/1

Trong lập trình multithreading, khi viết một hàm ta phải lưu ý đến tính chất thread-safe. Một hàm có tính thread-safe khi và chỉ khi nó vẫn hoạt động đúng đắn nếu ta sử dụng chúng trong multiple concurent threads (nhiều threads chạy song song).

Ở bài viết trước, (blog) Singleton in single-threading environment, hầu hết các mẫu thiết kế singleton không đảm bảo rằng chỉ có một instance được tạo ra, khi ta sử dụng trong môi trường multithreading. Nếu chương trình bạn có 10 threads, khi gọi getInstance() đồng loạt ở 10 threads, có thể ta có 1 instance, cũng có thể có 2 intances, ..., hay 10 instances.

Hầu hết chứ không phải là tất cả! Mẫu C++ (nên.2) có tính thread-safe, trong môi trường singlethreading hay multithreading, cũng chỉ có 1 instance được khởi tạo. Các mẫu singleton không được khuyến khích ở bài trước cũng có tính thread-safe, nhưng tôi không dùng vì tôi định nghĩa singleton phải có tính Lazy initialization, hay ít ra thiết kế singleton không có tính Lazy initialization là mẫu thiết kế thiếu chuyên nghiệp, và chúng không được khuyến khích.

Bài viết này đề cập đến tính thread-safe của các mẫu Singleton. Đầu tiên là giải pháp của Bill Pugh cho Java :

Java : với cách thiết kế này ta không thể tạo class con DerivedSingleton, thừa kế từ class cha Singleton.

 1 public class Singleton {
 2   private Singleton() {}
 3 
 4   private static class SingletonHolder { 
 5     private static final Singleton INSTANCE = new Singleton();
 6   }
 7 
 8   public static Singleton getInstance() {
 9     return SingletonHolder.INSTANCE;
10   }
11 }

Cách giải quyết của Bill Pugh cũng tương tự mẫu C++ (nên.2), và ta không tạo được DerivedSingleton thừa kế từ Singleton.
Một cách tiếp cận khác tuân theo truyền thống đó là dùng khóa để đồng bộ hóa trong lập trình song song. Java hỗ trợ rất tốt cho multithreading programming: mọi thứ đều có thể là khóa.Chỉ cần áp từ khóa synchronized lên cho nó:

1 synchronized(everthing) { 
2 // ở đây, dữ liệu được bảo vệ bởi ổ khóa "everything" 
3 }

Giải pháp double-check được sử dụng từ sau thế hệ Java 5.0:

Java

 1 public class Singleton {
 2   private volatile static Singleton instance = null; 
 3   private Singleton(){}
 4 
 5   public static Singleton getInstance(){
 6     if(instance==null) {
 7       synchronized(Singleton.class){
 8         if(instance==null)  // double-check
 9         instance= new Singleton();
10       }
11     }
12     return instance;
13   }
14 }

Dựa vào cách tiếp cận này ta tự thiết kế khóa MutexSynchOperation (Synchronized Operation), vì C++ chuẩn không hỗ trợ multithreads (ta dùng thư viện của Posix Thread). Sau đây là mẩu thiết kế double-check dành cho C++

C++

instance mMutex của class Mutex có vai trò như cái khóa, còn instance synchronized của class SynchOperation bảo vệ toàn bộ dữ liệu trong scope mà nó tồn tại.

 1 class Mutex
 2 {
 3 public:
 4   Mutex() { pthread_mutex_init(&m_mutex, NULL); }
 5   ~Mutex() { pthread_mutex_destroy(&m_mutex); }
 6   class SynchOperation {
 7   public:
 8     SynchOperation(Mutex &data) : m_data(data)
 9       { pthread_mutex_lock(&m_data.m_mutex); }
10     ~SynchOperation() 
11       { pthread_mutex_unlock(&m_data.m_mutex); }
12   protected:
13     Mutex & m_data;
14   };
15 protected:
16   pthread_mutex_t m_mutex;
17   friend class ::Mutex::SynchOperation;
18 };

thread-safe singleton sử dụng Mutex

 1 // Header file (.h)
 2 
 3 class Singleton
 4 {
 5 public:
 6   static Singleton* getInstance();
 7 private:
 8   Singleton() {}
 9   ~Singleton() {}
10   static Singleton* instance;
11   static Mutex mMutex;
12 };
13 
14 // Source file (.cpp)
15 
16 Singleton* Singleton::instance = NULL;
17 Mutex Singleton::mMutex;
18 
19 Singleton* Singleton::getInstance()
20 {
21   if (instance == NULL)
22   {
23     Mutex::SynchOperation synchronized(mMutex);  
24     if (instance == NULL)      // double-check
25       instance = new Singleton();
26   }
27   return instance;
28 }

Comments