LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-16-2012, 01:09 AM   #1
Aquarius_Girl
Senior Member
 
Registered: Dec 2008
Posts: 4,731
Blog Entries: 29

Rep: Reputation: 940Reputation: 940Reputation: 940Reputation: 940Reputation: 940Reputation: 940Reputation: 940Reputation: 940
[C++] Creating a Mutex locker class - RAII


Code:
class mutexLocker
{
	private:
	/* Declaration of a Mutex variable `mutexA`. */
	pthread_mutex_t &mutexA;
	
	/* `mutexStatus` holds the return value of the function`pthread_mutex_lock `. 
	This value has to be returned to the callee so we need to preserve it in a class
	variable. */
	int             mutexStatus;

	public:
	/* Constructor attempts to lock the desired mutex variable. */
	mutexLocker (pthread_mutex_t argMutexVariable) 
	: mutexA (argMutexVariable)
	{
	    /* Return value is needed in order to know whether the mutex has been 
	    successfully locked or not. */
	    int mutexStatus = pthread_mutex_lock (&argMutexVariable);
	}
	
	/* Since the constructor can't return anything, we need to have a separate function
	which returns the status of the lock. */
	int getMutexLockStatus ()
	{
	    return mutexStatus;
	}
	
        /* We may need this Mutex variable as an argument for `pthread_cond_wait()`*/
	pthread_mutex_t getLockedMutex ()
	{
	    if (mutexStatus >= 0)
	        return mutexA;
	}
	
	/* The destructor will get called automatically whereever the callee's scope ends, and
	will get the mutex unlocked. */
	~mutexLocker ()
	{
	    if (mutexStatus >= 0)
	        pthread_mutex_unlock (&mutexA);
	}
};
What other functionalities should be provided in a DIY mutex locker class?

Last edited by Aquarius_Girl; 08-16-2012 at 06:36 AM.
 
Old 08-16-2012, 07:26 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
IMHO, you don't need the method to return the status; consider throwing an exception should a runtime error occur. After all, the point of the wrapper class is to avoid exposing OS-dependent interfaces to the user, right?

As for exposing the pthread_mutex_t, I also would not recommend doing that. The pthread_mutex_t should be an attribute of your Mutex class, not a reference to an external object (which could be destroyed, manipulated, etc). As for your ConditionMutex class, it should contain a Mutex object.

Here's some code I threw together in the past when trying to mimic the Boost Thread Library (I jokingly called it 'liteboost'):

mutex.hpp:
Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under 
# the terms of the GNU General Public License as published by the Free Software 
# Foundation, either version 3 of the License, or (at your option) any later 
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with 
#this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef LITE_BOOST_MUTEX_H
#define LITE_BOOST_MUTEX_H

#include <pthread.h>
#include <stdexcept>

namespace liteboost
{

class condition;

class mutex
{
  public:
    mutex(int kind = PTHREAD_MUTEX_DEFAULT)
    {
      pthread_mutexattr_t attr;

      if (pthread_mutexattr_init(&attr) != 0)
      {
        throw std::runtime_error("Mutex::initMutex() -- failed to init attr.");
      }

      if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0)
      {
        throw std::runtime_error("Mutex::initMutex() -- failed to set attr process type.");
      }

      if (pthread_mutexattr_settype(&attr, kind) != 0)
      {
        throw std::runtime_error("Mutex::initMutex() -- failed to set attr type.");
      }

      if (pthread_mutex_init(&m_mutex, &attr) != 0)
      {
        throw std::runtime_error("Mutex::initMutex() -- failed to init mutex attr.");
      }
    }

    ~mutex()
    {
      if (pthread_mutex_destroy(&m_mutex) != 0)
      {
        throw std::runtime_error("Mutex::~Mutex() -- unable to destroy the mutex.");
      }
    }


    class scoped_lock
    {
      public:
        scoped_lock(mutex& mutex) : m_mutex(mutex)
        {
          m_mutex.lock();
        }

        ~scoped_lock()
        {
          m_mutex.unlock();
        }

      private:
        mutex& m_mutex;
    };


  private:
    friend class condition;

    void lock()
    {
      if (pthread_mutex_lock(&m_mutex) != 0)
      {
        throw std::runtime_error("Mutex::lock() -- unable to lock the mutex.");
      }
    }

    void unlock()
    {
      if (pthread_mutex_unlock(&m_mutex) != 0)
      {
        throw std::runtime_error("Mutex::unlock() -- unable to unlock the mutex.");
      }
    }

    pthread_mutex_t* get_mutex()
    {
      return &m_mutex;
    }

    pthread_mutex_t m_mutex;
};

} // end namespace

#endif
condition.hpp:
Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under 
# the terms of the GNU General Public License as published by the Free Software 
# Foundation, either version 3 of the License, or (at your option) any later 
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with 
#this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef LITE_BOOST_CONDITION_H
#define LITE_BOOST_CONDITION_H

#include <liteboost/thread/mutex.hpp>
#include <pthread.h>
#include <sys/time.h>
#include <cerrno>
#include <limits>
#include <stdexcept>

namespace liteboost
{

class condition
{
  public:
    condition()
    {
      pthread_condattr_t attr;

      if (pthread_condattr_init(&attr) != 0)
      {
        throw std::runtime_error("condition(): pthread_condattr_init() failed.");
      }

      if (pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0)
      {
        throw std::runtime_error("condition(): pthread_condattr_setpshared() failed.");
      }

      if (pthread_cond_init(&m_cond, &attr) != 0)
      {
        throw std::runtime_error("condition(): pthread_condattr_init() failed.");
      }
    }

    ~condition()
    {
      if (pthread_cond_destroy(&m_cond) != 0)
      {
        throw std::runtime_error("~condition(): pthread_cond_destroy() failed.");
      }
    }

    void wait()
    {
      if (pthread_cond_wait(&m_cond, m_mutex.get_mutex()) != 0)
      {
        throw std::runtime_error("wait(): pthread_cond_wait() failed.");
      }
    }

    bool timed_wait(const unsigned int waitTime_ns)
    {
      static const unsigned int NANOSECS_PER_SEC  = 1000000000;
      static const unsigned int NANOSECS_PER_USEC = 1000;

      // Convert given nanosecond time into an abstime (absolute time)
      struct timeval td;
      gettimeofday(&td, 0);

      struct timespec t;
      t.tv_sec  = td.tv_sec +  (waitTime_ns / NANOSECS_PER_SEC);
      t.tv_nsec = (td.tv_usec * NANOSECS_PER_USEC) + (waitTime_ns % NANOSECS_PER_SEC);

      // Check for overflow in the computed nanoseconds
      if ((unsigned int)t.tv_nsec >= NANOSECS_PER_SEC)
      {
        t.tv_sec  += 1;
        t.tv_nsec -= NANOSECS_PER_SEC;
      }

      // Loop until the condition signal is received, or a timeout occurs
      while (1)
      {
        switch (pthread_cond_timedwait(&m_cond, m_mutex.get_mutex(), &t))
        {
          // Everything is ok; condition-lock was obtained.
          case 0:
              return true;

          // Timeout occurred before receiving a signal; condition-lock was not obtained.
          case ETIMEDOUT:
              return false;

          // Error occurred.
          default:
              throw std::runtime_error("timed_wait(): pthread_cond_timedwait() failed.");
        }
      }
    }

    void signal()
    {
      if (pthread_cond_signal(&m_cond) != 0)
      {
        throw std::runtime_error("signal(): phread_cond_signal() failed.");
      }
    }

    void broadcast()
    {
      if (pthread_cond_broadcast(&m_cond) != 0)
      {
        throw std::runtime_error("signal(): phread_cond_broadcast() failed.");
      }
    }

    class scoped_cond_lock
    {
      public:
        scoped_cond_lock(condition& cond) : m_cond(cond)
        {
          m_cond.lock();
        }

        ~scoped_cond_lock()
        {
          m_cond.unlock();
        }

      private:
        condition& m_cond;
    };

  private:
    void lock()
    {
      m_mutex.lock();
    }

    void unlock()
    {
      m_mutex.unlock();
    }

    pthread_cond_t m_cond;
    mutex          m_mutex;
};

} // end namespace

#endif
Sample usage:
Code:
#include "liteboost/thread/mutex.hpp"
#include <map>
#include <stdexcept>

class SharedObject
{
  private:
    typedef std::map<unsigned int, unsigned int> MyMap;
    typedef MyMap::const_iterator                MyMapIter;

  public:
    static SharedObject& instance();

    void insert(const unsigned int key, const unsigned int value);

    unsigned int getValue(const unsigned int key);

  private:
    SharedObject() {}

    MyMap            m_map;
    liteboost::mutex m_mutex;
};


SharedObject&
SharedObject::instance()
{
  static SharedObject obj;
  return obj;
}


void
SharedObject::insert(const unsigned int key, const unsigned int value)
{
  liteboost::mutex::scoped_lock lock(m_mutex);

  m_map[key] = value;
}


unsigned int
SharedObject::getValue(const unsigned int key)
{
  liteboost::mutex::scoped_lock lock(m_mutex);

  MyMapIter it = m_map.find(key);

  if (it == m_map.end())
  {
    throw std::runtime_error("SharedObject::getValue() -- key not found!");
  }

  return it->second;
}

Last edited by dwhitney67; 08-16-2012 at 07:29 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] [C++] Need some serious help creating a 'class' and linking multiple source codes mothergoose729 Programming 9 10-13-2010 03:15 PM
TROUBLE in child_init_hook: BDB no dbS: Unknown locker ID: datu_0638561 General 0 01-26-2009 06:51 PM
LXer: Scolarships from Red Hat for creating world class open source software LXer Syndicated Linux News 0 05-02-2006 03:03 PM
LXer: MP3tunes' Locker sounds good LXer Syndicated Linux News 0 02-09-2006 09:31 PM
Screen locker question Wynd Linux - General 1 09-15-2003 11:02 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:51 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration