Handling access to shared resources

A

Angus

Hello

I am having a problem with access to a shared std::list. The list is
accessed via different threads and I use a mutex lock/unlock to ensure
that only one process can work on the list at any one time. The
trouble is the lock and unlock is scattered through the code. I am
having problems where I do a lock but there is no unlock and the code
gets stuck. It is quite tricky to debug of course.

Does anyone have any tips on how to handle this problem. Should I use
some global/singleton accessor function to access the list? But I do
need to perhaps edit/delete/add to the list. so how best to handle?

Angus
 
S

SG

[...] accessed via different threads and I use a mutex lock/unlock
to ensure that only one process can work on the list at any one
time.  The trouble is the lock and unlock is scattered through the
code.  I am having problems where I do a lock but there is no unlock
and the code gets stuck.  It is quite tricky to debug of course.

Does anyone have any tips on how to handle this problem. Should I use
some global/singleton accessor function to access the list? But I do
need to perhaps edit/delete/add to the list. so how best to handle?

You should make use of RAII for the locks. If you're using a C API for
threads you may want to write your own "lock" class that can be used
like this:

void foo() {
lock l (&mutex);
// do something
} // automatically unlock mutex in destructor of 'l'

This should be the preferred method for locking/unlocking mutexes.
Something like this is supported by the Boost.Threads library and will
be supported by the next C++ standard library.

Cheers!
SG
 
J

Jerry Coffin

(e-mail address removed)>, (e-mail address removed)
says...
Hello

I am having a problem with access to a shared std::list. The list is
accessed via different threads and I use a mutex lock/unlock to ensure
that only one process can work on the list at any one time. The
trouble is the lock and unlock is scattered through the code. I am
having problems where I do a lock but there is no unlock and the code
gets stuck. It is quite tricky to debug of course.

Does anyone have any tips on how to handle this problem. Should I use
some global/singleton accessor function to access the list? But I do
need to perhaps edit/delete/add to the list. so how best to handle?

Write a class that supports the actual operations you care about, and
implement the atomicity inside of those individual operations. At least
for adding and deleting, this can be pretty simple:


class storage {
std::list<whatever> list;
MUTEX m;
public:
void add(whatever const &a) {
acquire(m);
list.insert(a);
}

void delete(whatever const &a) {
acquire(m);
std::list<whatever>::iterator pos;
pos = list.find(a);
list.remove(pos);
}
};

It's harder to make suggestions about editing. Just for example, without
knowing more about what you're doing, it's impossible to guess whether
you need in-place editing, or whether it's reasonable to remove one
value and insert a new one.

Though it's necessarily all that directly responsive to your question,
I'd also note that IME, std::list (and linked lists in general) are only
rarely a good choice of data structure. There are _usually_ better
choices. When you need atomic operations, that percentage goes up quite
a bit further still. The major advantage of a linked list is being able
to keep accessors (pointers, iterators, etc.) to individual items in the
list, but those are often quite difficult to reconcile with atomic
operations.
 
J

James Kanze

(e-mail address removed)>,
(e-mail address removed) says...
Write a class that supports the actual operations you care
about, and implement the atomicity inside of those individual
operations. At least for adding and deleting, this can be
pretty simple:
class storage {
std::list<whatever> list;
MUTEX m;
public:
void add(whatever const &a) {
acquire(m);
list.insert(a);
}
void delete(whatever const &a) {
acquire(m);
std::list<whatever>::iterator pos;
pos = list.find(a);
list.remove(pos);
}
};

I suspect that this example is incomplete. It's not clear what
"acquire(m)" does, but if it simply acquires the lock (as it's
name suggests), then you're missing the releases. And of
course, since you can also exit the sequence because of an
exception (at least in the case of add), you have to ensure that
it is called then as well---the classical scoped lock pattern
should definitely be used.
 
S

SG

I agree with "SG", use RAII to solve this.
Check for more example out Andrei Alexandrescu  example of LockingPtr
at the following Dr.Dobbs articlehttp://www.ddj.com/cpp/184403766

Hmm... this article is 8 years old and covers "volatile" in a way
that's not in line with what Herb Sutter has to say on this topic [1]
("volatile" isn't about multithreading. It's about funky memory areas
like memory-mapped devices). His "volatile type safety hack" for
preventing access without locking is an interesting idea, though.

[1] http://www.ddj.com/hpc-high-performance-computing/212701484

Cheers!
SG
 
J

Jerry Coffin

I suspect that this example is incomplete. It's not clear what
"acquire(m)" does, but if it simply acquires the lock (as it's
name suggests), then you're missing the releases. And of
course, since you can also exit the sequence because of an
exception (at least in the case of add), you have to ensure that
it is called then as well---the classical scoped lock pattern
should definitely be used.

Sorry -- I should have added a comment that this was really pseudo-code,
not intended to be fed to a compiler as-is.

The intent, however, was that the 'acquire' be a scoped lock -- it might
not be the best name for it, but given the nature of C++, (and the way I
program) using a lock that wasn't based on RAII is something that would
hardly even occur to me anymore...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top