使用named_mutex实现读写锁,实现进程之间读共享写独占

代码

  • 代码的名称是read_write_mutex.h
  • 这个代码可用,但是未优化,还存在冗余的代码
  • 如果涉及到进程挂掉了,造成进程堵塞,如何解决?还未涉及
//#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP

//  (C) Copyright 2006-8 Anthony Williams
//  (C) Copyright 2012 Vicente J. Botet Escriba
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/thread_interruption.hpp>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/assert.hpp>

#include <boost/config/abi_prefix.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>

namespace bip = boost::interprocess;
namespace chy
{
    class shared_mutex
    {
    private:
        class state_data
        {
        public:
            state_data () :
                    shared_count(0),
                    exclusive(false),
                    upgrade(false),
                    exclusive_waiting_blocked(false)
            {}

            void assert_free() const
            {
                BOOST_ASSERT( ! exclusive );
                BOOST_ASSERT( ! upgrade );
                BOOST_ASSERT( shared_count==0 );
            }

            void assert_locked() const
            {
                BOOST_ASSERT( exclusive );
                BOOST_ASSERT( shared_count==0 );
                BOOST_ASSERT( ! upgrade );
            }

            void assert_lock_shared () const
            {
                BOOST_ASSERT( ! exclusive );
                BOOST_ASSERT( shared_count>0 );
                //BOOST_ASSERT( (! upgrade) || (shared_count>1));
                // if upgraded there are at least 2 threads sharing the mutex,
                // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
            }

            void assert_lock_upgraded () const
            {
                BOOST_ASSERT( ! exclusive );
                BOOST_ASSERT(  upgrade );
                BOOST_ASSERT(  shared_count>0 );
            }

            void assert_lock_not_upgraded () const
            {
                BOOST_ASSERT(  ! upgrade );
            }

            bool can_lock () const
            {
                return ! (shared_count || exclusive);
            }

            void exclusive_blocked (bool blocked)
            {
                exclusive_waiting_blocked = blocked;
            }

            void lock ()
            {
                exclusive = true;
            }

            void unlock ()
            {
                exclusive = false;
                exclusive_waiting_blocked = false;
            }

            bool can_lock_shared () const
            {
                return ! (exclusive || exclusive_waiting_blocked);
            }

            bool more_shared () const
            {
                return shared_count > 0 ;
            }
            unsigned get_shared_count () const
            {
                return shared_count ;
            }
            unsigned  lock_shared ()
            {
                return ++shared_count;
            }


            void unlock_shared ()
            {
                --shared_count;
            }

            bool unlock_shared_downgrades()
            {
                if (upgrade) {
                    upgrade=false;
                    exclusive=true;
                    return true;
                } else {
                    exclusive_waiting_blocked=false;
                    return false;
                }
            }

            void lock_upgrade ()
            {
                ++shared_count;
                upgrade=true;
            }
            bool can_lock_upgrade () const
            {
                return ! (exclusive || exclusive_waiting_blocked || upgrade);
            }

            void unlock_upgrade ()
            {
                upgrade=false;
                --shared_count;
            }

            //private:
            unsigned shared_count;
            bool exclusive;
            bool upgrade;
            bool exclusive_waiting_blocked;
        };



        state_data state;
//        boost::mutex state_change;
        bip::named_mutex state_change{bip::open_or_create,"mutex"};
//        boost::condition_variable shared_cond;
        bip::named_condition shared_cond{bip::open_or_create,"read"};
//        boost::condition_variable exclusive_cond;
        bip::named_condition exclusive_cond{bip::open_or_create,"write"};
        boost::condition_variable upgrade_cond;

        void release_waiters()
        {
            exclusive_cond.notify_one();
            shared_cond.notify_all();
        }

    public:

        BOOST_THREAD_NO_COPYABLE(shared_mutex)

        shared_mutex()
        {
        }

        ~shared_mutex()
        {
        }

        void lock_shared()
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
//            boost::unique_lock<bip::named_mutex>lk(state_change);
            boost::unique_lock<bip::named_mutex> lk(state_change);
            while(!state.can_lock_shared())
            {
                shared_cond.wait(lk);
            }
            state.lock_shared();
        }

        bool try_lock_shared()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            if(!state.can_lock_shared())
            {
                return false;
            }
            state.lock_shared();
            return true;
        }

//#if defined BOOST_THREAD_USES_DATETIME
//        bool timed_lock_shared(boost::system_time const& timeout)
//        {
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
//            boost::this_thread::disable_interruption do_not_disturb;
//#endif
            boost::unique_lock<boost::mutex> lk(state_change);
//            boost::unique_lock<bip::named_mutex>lk(state_change);
//
//            while(!state.can_lock_shared())
//            {
//                if(!shared_cond.timed_wait(lk,timeout))
//                {
//                    return false;
//                }
//            }
//            state.lock_shared();
//            return true;
//        }

//        template<typename TimeDuration>
//        bool timed_lock_shared(TimeDuration const & relative_time)
//        {
//            return timed_lock_shared(boost::get_system_time()+relative_time);
//        }
//#endif
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
        bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
        {
            return try_lock_shared_until(boost::chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
        bool try_lock_shared_until(const boost::chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//          boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(!state.can_lock_shared())
                //while(state.exclusive || state.exclusive_waiting_blocked)
            {
//              if(boost::cv_status::timeout==shared_cond.wait_until(lk,abs_time))
//              {
//                  return false;
//              }
            }
            state.lock_shared();
            return true;
        }
#endif
        void unlock_shared()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_lock_shared();
            state.unlock_shared();
            if (! state.more_shared())
            {
                if (state.upgrade)
                {
                    // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
                    // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
                    state.upgrade=false;
                    state.exclusive=true;
                    //lk.unlock();
                    upgrade_cond.notify_one();
                }
                else
                {
                    state.exclusive_waiting_blocked=false;
                    //lk.unlock();
                }
                release_waiters();
            }
        }

        void lock()
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while (state.shared_count || state.exclusive)
            {
                state.exclusive_waiting_blocked=true;
                exclusive_cond.wait(lk);
            }
            state.exclusive=true;
        }

#if defined BOOST_THREAD_USES_DATETIME
        bool timed_lock(boost::system_time const& timeout)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(state.shared_count || state.exclusive)
            {
                state.exclusive_waiting_blocked=true;
                if(!exclusive_cond.timed_wait(lk,timeout))
                {
                    if(state.shared_count || state.exclusive)
                    {
                        state.exclusive_waiting_blocked=false;
                        release_waiters();
                        return false;
                    }
                    break;
                }
            }
            state.exclusive=true;
            return true;
        }

        template<typename TimeDuration>
        bool timed_lock(TimeDuration const & relative_time)
        {
            return timed_lock(boost::get_system_time()+relative_time);
        }
#endif
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
        bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time)
        {
            return try_lock_until(boost::chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
        bool try_lock_until(const boost::chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//          boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(state.shared_count || state.exclusive)
            {
                state.exclusive_waiting_blocked=true;
//              if(boost::cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
//              {
//                  if(state.shared_count || state.exclusive)
//                  {
//                      state.exclusive_waiting_blocked=false;
//                      release_waiters();
//                      return false;
//                  }
//                  break;
//              }
            }
            state.exclusive=true;
            return true;
        }
#endif

        bool try_lock()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            if(state.shared_count || state.exclusive)
            {
                return false;
            }
            else
            {
                state.exclusive=true;
                return true;
            }

        }

        void unlock()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_locked();
            state.exclusive=false;
            state.exclusive_waiting_blocked=false;
            state.assert_free();
            release_waiters();
        }

        void lock_upgrade()
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
            {
                shared_cond.wait(lk);
            }
            state.lock_shared();
            state.upgrade=true;
        }

#if defined BOOST_THREAD_USES_DATETIME
        bool timed_lock_upgrade(boost::system_time const& timeout)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
            {
                if(!shared_cond.timed_wait(lk,timeout))
                {
                    if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
                    {
                        return false;
                    }
                    break;
                }
            }
            state.lock_shared();
            state.upgrade=true;
            return true;
        }

        template<typename TimeDuration>
        bool timed_lock_upgrade(TimeDuration const & relative_time)
        {
            return timed_lock_upgrade(boost::get_system_time()+relative_time);
        }
#endif
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
        bool try_lock_upgrade_for(const boost::chrono::duration<Rep, Period>& rel_time)
        {
            return try_lock_upgrade_until(boost::chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
        bool try_lock_upgrade_until(const boost::chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//          boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
            {
//              if(boost::cv_status::timeout == shared_cond.wait_until(lk,abs_time))
//              {
//                  if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
//                  {
//                      return false;
//                  }
//                  break;
//              }
            }
            state.lock_shared();
            state.upgrade=true;
            return true;
        }
#endif
        bool try_lock_upgrade()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
            {
                return false;
            }
            else
            {
                state.lock_shared();
                state.upgrade=true;
                state.assert_lock_upgraded();
                return true;
            }
        }

        void unlock_upgrade()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            //state.upgrade=false;
            state.unlock_upgrade();
            if(! state.more_shared() )
            {
                state.exclusive_waiting_blocked=false;
                release_waiters();
            } else {
                shared_cond.notify_all();
            }
        }

        // Upgrade <-> Exclusive
        void unlock_upgrade_and_lock()
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_lock_upgraded();
            state.unlock_shared();
//            while (state.more_shared())
//            {
//                upgrade_cond.wait(lk);
//            }
            state.upgrade=false;
            state.exclusive=true;
            state.assert_locked();
        }

        void unlock_and_lock_upgrade()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_locked();
            state.exclusive=false;
            state.upgrade=true;
            state.lock_shared();
            state.exclusive_waiting_blocked=false;
            state.assert_lock_upgraded();
            release_waiters();
        }

        bool try_unlock_upgrade_and_lock()
        {
//          boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_lock_upgraded();
            if(    !state.exclusive
                   && !state.exclusive_waiting_blocked
                   && state.upgrade
                   && state.shared_count==1)
            {
                state.shared_count=0;
                state.exclusive=true;
                state.upgrade=false;
                state.assert_locked();
                return true;
            }
            return false;
        }
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
        bool
        try_unlock_upgrade_and_lock_for(
                const boost::chrono::duration<Rep, Period>& rel_time)
        {
            return try_unlock_upgrade_and_lock_until(
                    boost::chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
        bool
        try_unlock_upgrade_and_lock_until(
                const boost::chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
            boost::this_thread::disable_interruption do_not_disturb;
#endif
//          boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_lock_upgraded();
            if (state.shared_count != 1)
            {
//              for (;;)
//              {
//                  boost::cv_status status = shared_cond.wait_until(lk,abs_time);
//                if (state.shared_count == 1)
//                  break;
//                if(status == boost::cv_status::timeout)
//                  return false;
//              }
            }
            state.upgrade=false;
            state.exclusive=true;
            state.exclusive_waiting_blocked=false;
            state.shared_count=0;
            return true;
        }
#endif

        // Shared <-> Exclusive
        void unlock_and_lock_shared()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_locked();
            state.exclusive=false;
            state.lock_shared();
            state.exclusive_waiting_blocked=false;
            release_waiters();
        }

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
        bool try_unlock_shared_and_lock()
        {
          boost::unique_lock<boost::mutex> lk(state_change);
          state.assert_lock_shared();
          if(    !state.exclusive
              && !state.exclusive_waiting_blocked
              && !state.upgrade
              && state.shared_count==1)
          {
            state.shared_count=0;
            state.exclusive=true;
            return true;
          }
          return false;
        }
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
            bool
            try_unlock_shared_and_lock_for(
                                const chrono::duration<Rep, Period>& rel_time)
        {
          return try_unlock_shared_and_lock_until(
                                 chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
            bool
            try_unlock_shared_and_lock_until(
                          const chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
          boost::this_thread::disable_interruption do_not_disturb;
#endif
          boost::unique_lock<boost::mutex> lk(state_change);
          state.assert_lock_shared();
          if (state.shared_count != 1)
          {
              for (;;)
              {
                cv_status status = shared_cond.wait_until(lk,abs_time);
                if (state.shared_count == 1)
                  break;
                if(status == cv_status::timeout)
                  return false;
              }
          }
          state.upgrade=false;
          state.exclusive=true;
          state.exclusive_waiting_blocked=false;
          state.shared_count=0;
          return true;
        }
#endif
#endif

        // Shared <-> Upgrade
        void unlock_upgrade_and_lock_shared()
        {
//            boost::unique_lock<boost::mutex> lk(state_change);
            boost::unique_lock<bip::named_mutex>lk(state_change);

            state.assert_lock_upgraded();
            state.upgrade=false;
            state.exclusive_waiting_blocked=false;
            release_waiters();
        }

#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
        bool try_unlock_shared_and_lock_upgrade()
        {
          boost::unique_lock<boost::mutex> lk(state_change);
          state.assert_lock_shared();
          if(    !state.exclusive
              && !state.exclusive_waiting_blocked
              && !state.upgrade
              )
          {
            state.upgrade=true;
            return true;
          }
          return false;
        }
#ifdef BOOST_THREAD_USES_CHRONO
        template <class Rep, class Period>
            bool
            try_unlock_shared_and_lock_upgrade_for(
                                const chrono::duration<Rep, Period>& rel_time)
        {
          return try_unlock_shared_and_lock_upgrade_until(
                                 chrono::steady_clock::now() + rel_time);
        }
        template <class Clock, class Duration>
            bool
            try_unlock_shared_and_lock_upgrade_until(
                          const chrono::time_point<Clock, Duration>& abs_time)
        {
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
          boost::this_thread::disable_interruption do_not_disturb;
#endif
          boost::unique_lock<boost::mutex> lk(state_change);
          state.assert_lock_shared();
          if(    state.exclusive
              || state.exclusive_waiting_blocked
              || state.upgrade
              )
          {
              for (;;)
              {
                cv_status status = exclusive_cond.wait_until(lk,abs_time);
                if(    ! state.exclusive
                    && ! state.exclusive_waiting_blocked
                    && ! state.upgrade
                    )
                  break;
                if(status == cv_status::timeout)
                  return false;
              }
          }
          state.upgrade=true;
          return true;
        }
#endif
#endif
    };

    typedef shared_mutex upgrade_mutex;
}

#include <boost/config/abi_suffix.hpp>

//#endif

测试代码

#include <boost/thread/thread.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/ref.hpp>

#include "read_write_mutex.h"

#include <string>
#include <mutex>

chy::shared_mutex global_mutex;
int global_num = 10;//全局变量,写者改变全局变量,读者读全局变量
namespace bip = boost::interprocess;
//bip::named_mutex global_mutex(bip::open_or_create,"mtx");

//读线程
void read_thread(std::string &name){
//    boost::lock_guard<bip::named_mutex> lock(global_mutex);//读锁定
//    bip::named_mutex global_mutex(bip::open_or_create,"mtx");
//    global_mutex.lock();
    boost::shared_lock<chy::shared_mutex> lock{global_mutex};
    printf("线程%s抢占了资源,global_num = %d\n",name.c_str(),global_num);
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    printf("线程%s释放了资源...\n",name.c_str());
//    global_mutex.unlock();
}

//写线程
void write_thread(std::string &name){
//    std::lock_guard<bip::named_mutex> lock(global_mutex);//写锁定
//    bip::named_mutex global_mutex(bip::open_or_create,"mtx");
//    global_mutex.lock();
    boost::lock_guard<chy::shared_mutex> lock{global_mutex};
    global_num++;//写线程改变数据的数值
    printf("线程%s抢占了资源,global_num = %d\n",name.c_str(),global_num);
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    printf("线程%s释放了资源...\n",name.c_str());
//    global_mutex.unlock();
}

int main(){
    std::string read_thread_r1 = "read_thread_r1";
    std::string read_thread_r2 = "read_thread_r2";
    std::string read_thread_r3 = "read_thread_r3";
    std::string read_thread_r4 = "read_thread_r4";
    std::string read_thread_r5 = "read_thread_r5";
    std::string write_thread_w1 = "write_thread_w1";
    std::string write_thread_w2 = "write_thread_w2";

    boost::thread_group tg;
    tg.create_thread(boost::bind(read_thread,boost::ref(read_thread_r1)));
    tg.create_thread(boost::bind(read_thread,boost::ref(read_thread_r2)));
    tg.create_thread(boost::bind(read_thread,boost::ref(read_thread_r3)));
    tg.create_thread(boost::bind(read_thread,boost::ref(read_thread_r4)));
    tg.create_thread(boost::bind(read_thread,boost::ref(read_thread_r5)));
    tg.create_thread(boost::bind(write_thread,boost::ref(write_thread_w1)));
    tg.create_thread(boost::bind(write_thread,boost::ref(write_thread_w2)));
    tg.join_all();

    return 0;
}

猜你喜欢

转载自blog.csdn.net/CHYabc123456hh/article/details/111658381
今日推荐