views:

64

answers:

3

I have a UDP based application that is implemented using a thread pool.

Messages are pushed onto a queue and the thread pool is woken when there are things to do or messages on the queue. The thread pool processes each of the messages and hands them off to session objects which hold some state. i.e. the UDP packets are part of a session and the session is reassembling a large block of data.

That session object needs to access a shared resource. However, another session object can also read from the resource, but not while it's being written to.

Now the problem is that the session objects DoWork method can be called from different threads and I need to prevent anyone writing to it. So to do that I need to put a lock around the resource.

Here is where the problem arises. If I use a standard mutex, it's not portable between threads so I will try to access the resource and should be able to put the data into the resource but I can't unless I'm the original thread that locked the resource.

It's as thought I need a session key to gain access to the resource rather than my thread id.

How do I get around this? boost shared_mutex here seems a bit limited in this case.

A: 

Sounds like you want a reader/writer lock.

chrisaycock
Ok, I knew I needed a reader/writer lock but what I didn't know and have just discovered by experimentation is that another thread can unlock the resource.
Matt H
A: 

What I'm doing is making the resource an object. A skeleton version looks like this:

e.g.

class Resource
{
public:
  enum {READ, WRITE};

  void Open(int mode=READ)
  {
     if (mode == WRITE){
       Lock();
       // Access resource
     } else if (mode == READ){
       // Try to get read access (scoped version)
        boost::shared_lock<boost::shared_mutex> read(lock_, boost::try_to_lock);
        if (!read){
            // throw exception
        }

        // Read access to resource
     }
  }

  Lock()
  {
    lock_.lock_upgrade();
    lock_.unlock_upgrade_and_lock();
  }

  Unlock()
  {
    lock_.unlock();
  }

private:
  boost::shared_mutex lock_;
}

Now I can have multiple readers. When I want to write to the resource (at any time) I can call Lock(). Open does it too. And can call Unlock when done. A different thread can unlock than the one that locked it.

Also, reads are prevented while writing, until unlock is called.

Matt H
A: 

As I understood oyu need multiple readers and one writer models. If so, you can create boost::shared_lock in "getter" and boost::unique_lock in "setter" (both definitely created against "lock_").

Re you method "Open": "read" is a local object and therefore it will be deleted when "Open" is completed. What means lock_ will be unlocked when you leave "Open" (shared_lock's destructor does this).

Gregory