2012-09-06 38 views
11

Tôi đã đọc nhiều câu hỏi xem xét khóa kiểm tra an toàn hai luồng (đối với người độc thân hoặc người lười biếng). Trong một số chủ đề, câu trả lời là mô hình hoàn toàn bị hỏng, những người khác đề xuất một giải pháp.C++ 11: Khóa kiểm tra an toàn kép để khởi tạo lười. Khả thi?

Vì vậy, câu hỏi của tôi là: Có cách nào để viết một mẫu khóa kiểm tra kép được kiểm tra toàn bộ chuỗi trong C++ không? Nếu vậy, nó trông như thế nào.

Chúng tôi có thể giả sử C++ 11, nếu điều đó giúp mọi thứ trở nên dễ dàng hơn. Theo như tôi biết, C++ 11 cải thiện mô hình bộ nhớ có thể mang lại những cải tiến cần thiết.

Tôi biết rằng điều đó có thể xảy ra trong Java bằng cách làm cho biến kiểm tra bảo vệ kép dễ bay hơi. Vì C++ 11 mượn các phần lớn của mô hình bộ nhớ từ một trong Java, nên tôi nghĩ nó có thể là có thể, nhưng làm thế nào?

+5

Nếu bạn có thể sử dụng C++ 11, hãy bỏ qua toàn bộ doanh nghiệp khóa đã chọn và sử dụng biến cục bộ tĩnh hoặc 'std :: call_once'. –

+0

Những người dân địa phương tĩnh có được khởi tạo lười biếng không? Và về 'call_once': Làm thế nào để đảm bảo rằng cuộc gọi một lần sẽ không viết tham chiếu không được tạo hoàn toàn cho biến? – gexicide

+3

có, người dân địa phương tĩnh được khởi tạo lười biếng theo cách an toàn chỉ. Và 'call_once' đảm bảo chủ đề chỉ được gọi một lần; và rằng không có lệnh gọi nào khác để trả về 'call_once' trước một lệnh thực thi hàm trả về (bạn có thể đọc thêm tại đây http://en.cppreference.com/w/cpp/thread/call_once). Nó hoạt động như thế nào. Hai điều này về cơ bản tồn tại, do đó bạn không muốn bận tâm với việc viết thêm lỗi việc kiểm tra khóa được kiểm tra kép. –

Trả lời

16

Đơn giản chỉ cần sử dụng một biến địa phương tĩnh cho Singletons uể oải khởi tạo, như vậy:

MySingleton* GetInstance() { 
    static MySingleton instance; 
    return &instance; 
} 

The (C++ 11) tiêu chuẩn đã đảm bảo rằng các biến tĩnh được khởi động một cách threadsafe và có vẻ như khả năng là thực hiện điều này ít nhất là mạnh mẽ và thực hiện như bất cứ điều gì bạn muốn viết cho mình.

Các threadsafety của việc khởi tạo có thể được tìm thấy trong §6.7.4 của (C++ 11) tiêu chuẩn:

Nếu kiểm soát vào tờ khai đồng thời trong khi các biến được khởi tạo, thực hiện đồng thời có trách nhiệm chờ hoàn thành quá trình khởi tạo.

+11

Điều này thật điên rồ. Tại sao, oh tại sao, bạn sẽ bao giờ trở lại một con trỏ nếu nó có thể ** không bao giờ ** là 'null'? –

+1

@MatthieuM: Chủ yếu là vì nó làm cho mọi người ít nghiêng để sao chép các đối tượng cơ bản. Tất nhiên một singleton được thiết kế tốt ** không nên ** có một nhà xây dựng bản sao, nhưng vẫn còn. Tôi thực sự không thấy cách trả về bằng tham chiếu so với giá trị trả về trong trường hợp đó. Vì vậy, tôi sẽ khó gọi đó là điên rồ. – Grizzly

+2

@Grizzly: Nếu một đối tượng không thể sao chép được, thì tùy thuộc vào đối tượng để thực thi điều đó. Nếu một đối tượng cần có một cá thể có thể truy cập trên toàn cầu, cần có một hàm để xử lý (giống như của bạn). Hai điều này là riêng biệt, và không có lý do gì để kết hợp chúng lại. Đây là lý do tại sao mẫu Singleton là ngu ngốc. – GManNickG

3

Vì bạn muốn xem triển khai DCLP C++ 11 hợp lệ, dưới đây là một.

Hành vi này hoàn toàn an toàn theo luồng và giống với GetInstance() trong câu trả lời của Grizzly.

std::mutex mtx; 
std::atomic<MySingleton *> instance_p{nullptr}; 

MySingleton* GetInstance() 
{ 
    auto *p = instance_p.load(std::memory_order_acquire); 

    if (!p) 
    { 
     std::lock_guard<std::mutex> lck{mtx}; 

     p = instance_p.load(std::memory_order_relaxed); 
     if (!p) 
     { 
      p = new MySingleton; 
      instance_p.store(p, std::memory_order_release); 
     } 
    } 

    return p; 
} 
+0

Trong thực tế, bạn muốn khai báo các biến 'mtx' và' instance_p' của bạn dưới dạng các globals bên ngoài hàm, chứ không phải là statics bên trong hàm, vì nếu không bạn sẽ trả giá kiểm tra nội bộ của trình biên dịch về khởi tạo 'mtx' và' instance_p' trên cuộc gọi _every_, đánh bại điểm kiểm tra kép (vì hiệu suất khôn ngoan bạn cũng có thể khai báo singleton là tĩnh). – BeeOnRope

+0

@BeeOnRope Điểm hợp lệ .. Tôi đã thực hiện thay đổi đó. – LWimsey

+0

Bạn có thể muốn thêm rằng về cơ bản bạn không bao giờ muốn viết mã này mặc dù. Câu trả lời của Grizzly ngắn gọn hơn cộng với trình biên dịch có thể chèn thêm ma thuật trong tương lai để làm cho nó nhanh hơn mã này. – gexicide

Các vấn đề liên quan