2010-02-12 24 views
9

Tôi có một lớp học được truy cập từ nhiều chủ đề. Cả hai hàm getter và setter đều được bảo vệ bằng các khóa. Các khóa cho các hàm getter có cần thiết không? Tại sao?hiện một chức năng getter cần một mutex?

class foo { 
public: 
    void setCount (int count) { 
     boost::lock_guard<boost::mutex> lg(mutex_); 
     count_ = count; 
    } 

    int count() { 
     boost::lock_guard<boost::mutex> lg(mutex_); // mutex needed? 
     return count_; 
    } 

private: 
    boost::mutex mutex_; 
    int count_; 
}; 

Trả lời

13

Cách duy nhất để bạn có thể thực hiện việc khóa là nếu bạn có thể thuyết phục bản thân rằng hệ thống sẽ chuyển biến bảo vệ nguyên tử trong mọi trường hợp. Nếu bạn không thể chắc chắn về điều đó vì một lý do nào đó, thì bạn sẽ cần đến mutex. Đối với một kiểu đơn giản như int, bạn có thể thuyết phục bản thân điều này là đúng, tùy thuộc vào kiến ​​trúc và giả định rằng nó được căn chỉnh đúng cho việc truyền một lệnh. Đối với bất kỳ loại nào phức tạp hơn thế này, bạn sẽ phải có khóa.

4

Nếu bạn không có mutex quanh getter và chuỗi đang đọc nó trong khi một chuỗi khác đang viết, bạn sẽ nhận được kết quả buồn cười.

+0

Không nhất thiết. Đọc và viết một 'int' có lẽ là hoạt động nguyên tử. Tất nhiên đây là kiến ​​trúc phụ thuộc và không di động. – Dan

+2

Chính xác - đó là hành vi không xác định. Sẽ tốt hơn nếu bạn có chi phí trên một khóa, thay vì bộ nhớ bị hỏng. –

+0

Thông thường, có.Nhưng nếu bạn có nhu cầu chứng minh để tăng hiệu suất, có thể bỏ qua khóa. Xem câu trả lời của tôi. – Dan

2

trong bạn trường hợp có thể không, nếu CPU của bạn là 32 bit, tuy nhiên nếu số là một đối tượng phức tạp hoặc cpu cần nhiều hơn một hướng dẫn để cập nhật giá trị của nó, sau đó có

5

là mutex thực sự chỉ bảo vệ một đơn int? Nó tạo nên sự khác biệt - nếu đó là kiểu dữ liệu phức tạp hơn, bạn chắc chắn cần khóa.

Nhưng nếu nó chỉ là một int, và bạn chắc chắn rằng int là một loại nguyên tử (ví dụ, bộ vi xử lý sẽ không phải thực hiện hai bộ nhớ riêng biệt đọc để nạp int vào một thanh ghi), và bạn đã làm chuẩn các hiệu suất và xác định bạn cần hiệu suất tốt hơn, sau đó bạn có thể xem xét thả khóa từ cả getter và setter. Nếu bạn làm như vậy, hãy đảm bảo hội đủ điều kiện là intvolatile. Và viết một bình luận giải thích lý do tại sao bạn không có bảo vệ mutex, và trong những điều kiện bạn sẽ cần nó nếu lớp thay đổi.

Ngoài ra, hãy cẩn thận rằng bạn không có mã như thế này:

void func(foo &f) { 
    int temp = f.count(); 
    ++temp; 
    f.setCount(temp); 
} 

Đó không phải là threadsafe, bất kể bạn sử dụng một mutex hay không. Nếu bạn cần làm điều gì đó như vậy, bảo vệ mutex phải nằm ngoài các hàm setter/getter.

1

Khóa cần thiết để truy cập hàng loạt vào tài nguyên được chia sẻ. Trong trường hợp cụ thể của bạn, bạn có thể lấy đi chỉ với atomic integer operations nhưng nói chung, đối với các đối tượng lớn hơn yêu cầu nhiều giao dịch bus, bạn cần khóa để đảm bảo rằng người đọc luôn thấy đối tượng nhất quán.

1

Phụ thuộc vào việc triển khai chính xác đối tượng đang bị khóa. Tuy nhiên, nói chung bạn không muốn ai đó sửa đổi (thiết lập?) Một đối tượng trong khi người khác đang trong quá trình đọc (nhận?) Nó. Cách dễ nhất để ngăn chặn điều đó là để người đọc khóa nó.

Trong các thiết lập phức tạp, khóa sẽ được triển khai theo cách mà mọi người có thể đọc cùng một lúc, nhưng không ai có thể viết thư trong khi bất kỳ ai đang đọc và không ai có thể đọc khi đang viết.

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