Aparte del hecho de que no es necesario tirar desde el constructor en su caso específico, porque pthread_mutex_lock
actually returns an EINVAL if your mutex has not been initialized y se puede tirar después de la llamada a lock
como se hace en std::mutex
:
void
lock()
{
int __e = __gthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
continuación, en general arrojando desde constructores está bien para adquisición errores durante la construcción, y de acuerdo con RAII (Recurso-adquisición-es-Inicialización) paradigma de programación.
Marque esta 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)
}
Enfoque sobre estos estados:
static std::mutex mutex
std::lock_guard<std::mutex> lock(mutex);
std::ofstream file("example.txt");
La primera declaración es RAII y noexcept
.En (2) está claro que RAII se aplica en lock_guard
y realmente puede throw
, mientras que en (3) ofstream
parece no ser RAII, ya que el estado de los objetos debe verificarse llamando al is_open()
que comprueba el indicador failbit
.
A primera vista parece que no se ha decidido sobre lo que la forma estándar y en el primer caso std::mutex
no lanza en la inicialización, * en contraste con la implementación OP *. En el segundo caso arrojará lo que sea que se arroje desde std::mutex::lock
, y en el tercero no hay lanzamiento en absoluto.
notar las diferencias:
(1) puede ser declarado estática, y realmente será declarada como una variable miembro (2) nunca realmente se espera para ser declarado como una variable miembro (3) es se espera que se declare como una variable miembro, y el recurso subyacente puede no estar siempre disponible.
Todos estos formularios son RAII; para resolver esto, uno debe analizar RAII.
- de recursos: su objeto
- Adquisición (asignación): usted objeto que está siendo creado
- inicialización: el objeto está en su estado invariante
Esto no requiere que para inicializar y conecta todo en la construcción. Por ejemplo, cuando crearía un objeto de cliente de red, en el momento de la creación no lo conectaría al servidor, ya que es una operación lenta con fallas. En su lugar, escribiría una función connect
para hacer justamente eso. Por otro lado, puede crear los búferes o simplemente establecer su estado.
Por lo tanto, su problema se reduce a la definición de su estado inicial. Si en su caso su estado inicial es , se debe inicializar mutex y luego debe lanzar desde el constructor. Por el contrario, está bien no inicializar entonces (como se hace en std::mutex
), y definir su estado invariable como se crea mutex. En cualquier caso, el invariante no está comprometido necesariamente por el estado de su objeto miembro, ya que el objeto mutex_
muta entre locked
y unlocked
a través de Mutex
, los métodos públicos Mutex::lock()
y 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
};
Otro enlace sobre el tema relacionado: http://www.writeulearn.com/exception-constructor/ –
Bueno, está bien tirar desde los ctors tanto como desde cualquier otra función, dicho esto, se debe lanzar con cuidado de cualquier función. – g24l
Algo no relacionado: ¿por qué no eliminar los métodos de bloqueo/desbloqueo, y bloquear directamente el mutex en el constructor y desbloquear en el destructor?De esta manera, simplemente declarando una variable automática en un alcance automáticamente bloquear/desbloquear, sin necesidad de ocuparse de excepciones, devoluciones, etc ... Ver 'std :: lock_guard' para una implementación similar. –