Aquarius_Girl
Aquarius_Girl

Reputation: 22936

Which kind of code is considered exception safe?

A code which handles the exceptions well is called an exception safe code? Is this correct?

From here: https://codereview.stackexchange.com/a/9759/11619

You use lock/unlock pairs for the mutex. This is not exception safe. So I would create an object that will do the lock in the constructor and unlock in the destructor then use this to lock your mutexs. This will make your code more exception safe.

class MutexLocker
{
    pthread_mutex_t&  mutex;
    MutextLocker(pthread_mutex_t& mutex)
        : mutex(mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    ~MutexLocker()
    {
        pthread_mutex_unlock(&mutex);
    }
};

In which way is the above shown code exception safe? I don't see any exception handling over there.

Or does exception safe code mean where we can "add" the exception handling? So, the above shown code can be made exception safe by adding exception handling, but it isn't now?

Upvotes: 5

Views: 2506

Answers (6)

Arya Pourtabatabaie
Arya Pourtabatabaie

Reputation: 734

The code you provided serves the purpose well. Simply because when execution leaves the block in which the MutexLocker object is defined, the object is destroyed and the mutex is released as per its destructor. This holds no matter the reason for the exit.

You don't have to code this class yourself though. The C++ standard specifies a class named lock_guard that does exactly that.

http://en.cppreference.com/w/cpp/thread/lock_guard

Upvotes: 0

Matthieu M.
Matthieu M.

Reputation: 300029

Exception Safety is not about handling exceptions, it is about guaranteeing a number of properties about the program even in the presence of exceptions.

You can usually speak about the exception safety level of a given method:

  • No Guarantee: this method is exception unsafe, that is no guarantee is made, at all.
  • Basic Exception Guarantee: in case of exception no resource is leaked and the classes involved are still usable (but their state is unspecified), that is no memory leak, no file handle leak, no mutex leak and the invariants of the instances involved are still verified.
  • Strong Exception Guarantee: in case of exception, all state is reversed to what it was prior to beginning. This is a transaction like semantic.
  • NoThrow Guarantee: this method does not throw, it always succeeds.

In general, the NoThrow Guarantee only applies to the simplest methods (ie .size() on a vector for example) and the Strong Exception Guarantee may be costly to implement (being able to revert the effect or operating on a copy of the state may not be cheap).

On the other hand, the Basic Exception Guarantee is just that: Basic. Without it, safely operating a program is just impossible, so this is the least guarantee that is acceptable. If you leak resources or leave classes in an unusable state, the program may not be able to operate further.

This is why there is such an emphasis on RAII whenever exceptions are mentionned. Because RAII guarantees automatic cleanup of resources (memory, mutexes, files) whatever the path execution (regular return or exception) it is particularly desirable. However, RAII itself is not sufficient.

Related: Herb Sutter's GotW entry about Exception Safety and Exception Specifications.

Upvotes: 8

Mankarse
Mankarse

Reputation: 40633

"Exception safe" is a fairly overloaded term, but I would use it to describe sections of code which can have exceptions thrown through them and still maintain certain invariants (such as - nothing changes, no resources are leaked, all objects keep a valid state).

As an example, your void * printHello (void* threadId) function is correct (in that it always matches pthread_mutex_lock (&demoMutex) with pthread_mutex_unlock (&demoMutex)), but if someone changed the section in the middle so that it could throw an exception (for example, by setting the throw flags on std::cout), then your code would then permanently lock demoMutex, with no hope for it ever being released. This would constitute a bug in your program. void * printHello (void* threadId) is said to be "exception unsafe" because of this way in which bugs can easily be introduced into your program by adding exception handling to seemingly unrelated parts.

Using a RAII class to manage resources a good way to go about writing exception safe code (and is the resource management style to use in C++), because it avoids the need for duplicate manual cleanup in catch(...) blocks, and it enforces the cleanup of resources by using the type system.

Upvotes: 2

BЈовић
BЈовић

Reputation: 64253

A code which handles the exceptions well is called an exception safe code?

Yes, but you do not say what well is. This is a good read on exception safety.

In which way is the above shown code exception safe?

That code is not exception safe in itself. That is meant to be used in a exception safe code. For example :

void bar()
{
  throw std::runtime_error( "lala" );
}

void foo()
{
  pthread_mutex_lock(&mutex);

  bar();

  // OPS! mutex not unlocked
  pthread_mutex_unlock(&mutex);
}

This problem is solved by using the class that automatically unlock the exception. Next example has exception handling with strong guarantees :

void foo()
{
  MutexLocker locker( mutex );

  try {
    bar();
  } catch ( const std::runtime_error & )
  {
    // revert changes
  }
}

Upvotes: 1

Bo Persson
Bo Persson

Reputation: 92321

You don't have to handle an exception to be exception safe. You just have to survive when an exception is thrown.

The MutexLocker helps you do this by unlocking the mutex when you leave the scope. It doesn't matter if you leave by a return statement or because an exception is thrown.

Upvotes: 3

Willem Hengeveld
Willem Hengeveld

Reputation: 2776

the MutexLocker destructor is always called, also when an exception was raised in the block where it was constructed.

that is what makes a construct using your MutexLocker exception safe.

Upvotes: 3

Related Questions