Ngoài thực tế mà bạn không cần phải ném từ các nhà xây dựng trong trường hợp cụ thể của bạn vì pthread_mutex_lock
actually returns an EINVAL if your mutex has not been initialized và bạn có thể ném sau khi cuộc gọi đến lock
như được thực hiện trong std::mutex
:
void
lock()
{
int __e = __gthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
sau đó trong nói chung ném từ các nhà thầu là ok cho mua lại lỗi trong khi xây dựng và tuân theo mô hình lập trình RAII (Nguồn-chuyển đổi-đang-khởi tạo).
Kiểm tra này example on RAII
void write_to_file (const std::string & message) {
// mutex to protect file access (shared across threads)
static std::mutex mutex;
// lock mutex before accessing file
std::lock_guard<std::mutex> lock(mutex);
// try to open file
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// write message to file
file << message << std::endl;
// file will be closed 1st when leaving scope (regardless of exception)
// mutex will be unlocked 2nd (from lock destructor) when leaving
// scope (regardless of exception)
}
Tập trung vào các báo cáo:
static std::mutex mutex
std::lock_guard<std::mutex> lock(mutex);
std::ofstream file("example.txt");
Câu lệnh đầu tiên là RAII và noexcept
.Trong (2) rõ ràng rằng RAII được áp dụng trên lock_guard
và nó thực sự có thể throw
, trong khi ở (3) ofstream
có vẻ không phải là RAII, vì trạng thái đối tượng phải được kiểm tra bằng cách gọi is_open()
để kiểm tra cờ failbit
.
Thoạt nhìn có vẻ như nó là chưa quyết định về những gì nó chuẩn cách và trong trường hợp đầu tiên std::mutex
không ném trong phần khởi tạo * trái ngược với thực hiện OP *. Trong trường hợp thứ hai nó sẽ ném bất cứ điều gì được ném từ std::mutex::lock
, và trong thứ ba không có ném cả.
Chú ý sự khác biệt:
(1) có thể được khai báo tĩnh, và thực sự sẽ được công bố như là một biến thành viên (2) Sẽ không bao giờ thực sự được dự kiến sẽ được công bố như là một biến thành viên (3) dự kiến sẽ được khai báo dưới dạng biến thành viên và tài nguyên cơ bản có thể không luôn có sẵn.
Tất cả các biểu mẫu này là RAII; để giải quyết vấn đề này, người ta phải phân tích RAII.
- Resource: đối tượng của bạn
- Acquisition (phân bổ): bạn đối tượng được tạo ra
- Khởi tạo: đối tượng của bạn ở trạng thái bất biến của nó
này không yêu cầu bạn phải khởi tạo và kết nối mọi thứ trên công trình. Ví dụ khi bạn sẽ tạo một đối tượng khách hàng mạng, bạn sẽ không thực sự kết nối nó với máy chủ khi tạo, vì nó là một hoạt động chậm với các lỗi. Thay vào đó, bạn sẽ viết một hàm connect
để thực hiện điều đó. Mặt khác, bạn có thể tạo bộ đệm hoặc chỉ đặt trạng thái của bộ đệm.
Do đó, vấn đề của bạn sẽ giảm xuống để xác định trạng thái ban đầu của bạn. Nếu trong trường hợp của bạn, trạng thái ban đầu của bạn là mutex phải được khởi tạo thì bạn nên ném từ hàm tạo. Ngược lại nó chỉ là tốt để không khởi tạo sau đó (như được thực hiện trong std::mutex
), và xác định trạng thái bất biến của bạn là mutex được tạo ra. Ở bất kỳ mức nào, bất biến không nhất thiết phải bị xâm phạm bởi trạng thái đối tượng thành viên của nó, kể từ khi đối tượng mutex_
biến đổi giữa locked
và unlocked
thông qua phương thức công khai Mutex::lock()
và Mutex::unlock()
.
class Mutex {
private:
int e;
pthread_mutex_t mutex_;
public:
Mutex(): e(0) {
e = pthread_mutex_init(&mutex_);
}
void lock() {
e = pthread_mutex_lock(&mutex_);
if(e == EINVAL)
{
throw MutexInitException();
}
else (e) {
throw MutexLockException();
}
}
// ... the rest of your class
};
Một liên kết khác có liên quan đến chủ đề: http://www.writeulearn.com/exception-constructor/ –
Vâng, bạn có thể bỏ qua các ctors nhiều như nó là từ bất kỳ chức năng nào khác, điều đó được cho là bạn nên cẩn thận từ bất kỳ chức năng nào. – g24l
Một cái gì đó không liên quan: tại sao không loại bỏ khóa/mở khóa phương pháp của bạn, và trực tiếp khóa mutex trong constructor và mở khóa trong destructor?Bằng cách đó, chỉ cần khai báo một biến tự động trong một phạm vi tự động khóa/mở khóa, không cần phải quan tâm đến các ngoại lệ, trả về, v.v ... Xem 'std :: lock_guard' để thực hiện tương tự. –