I was about to write a comment but it became too long.
This kind of classes should not be copyable.
Lets take a look to the destructor:
~sync_lock() {
pthread_cond_destroy( &cond );
pthread_mutex_destroy( &mtx );
}
It will destroy the mutex
and the condition
, invalidating any copy of the object you have.
This line:
lock_map[lid] = sync_lock();
Will do the following:
- Create a temporary object (indexing operator)
- Create another temporary object (call to
sync_lockl()
)
- Call assignment operator in the first object (point
(1)
)
- Destroy the object created in
(2)
The consequences of this procedure are disastrous:
The mutex
and the condition
initialized in point (1)
will never get destroyed because they were overwritten by the assignment operator
If the code had the following format:
{
sync_lock lock; // line 29
lock_map[lid] = lock; // line 30
} // line 31
The mutex
and condition
created in line 29
will be destroyed after line 31
, when lock
's destructor gets called.
Si, my advice, never make classes having this kind of resources copyable, specially when dealing with synchronization objects. If you want to put them in a container, fine, but use a pointer.
With C++11 you can make them movable, that will solve most of the problems of the current solution, but C++ also has std::mutex
and std::condition
so maybe you can rely on them instead of pthread
.
Update: Based on the std::map
implementation in GCC 4.7 (optimizations aside)
mapped_type&
operator[](const key_type& __k)
{
// concept requirements
__glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)
iterator __i = lower_bound(__k);
// __i->first is greater than or equivalent to __k.
if (__i == end() || key_comp()(__k, (*__i).first))
// inserts new object
__i = insert(__i, value_type(__k, mapped_type()));
return (*__i).second;
}