修改BOOST(二)

    技术2022-05-11  129

    修改BOOST()

     

    boost提供的thread_specific_ptr用起来很简便。但是TLS的可用索引数量是有限的。特别是在的DLL中,如果第一个进程加载的DLL模块用去了n个索引,第二个进程加载相同模块时可用索引就减少n个,Windows下可用的索引也就一千个左右(我没有去查资料,只是凭记忆写的,如果有错误,可以在下面的讨论中指出,不过大概是这个意思)。不过可以只用一个TLS索引来保存所有的与线程相关的数据。下面是源代码。

    1.头文件vtss.hpp

    //vtss.hpp。虚拟TSS索引

    #ifndef _VTSS_H

    #define _VTSS_H

    #include <boost/thread/tss.hpp>

     

     

    namespace boost {

     

        namespace detail {

            class vtss

            {

            public:

                vtss(void (*cleanup)(void*)=0);

                ~vtss();

     

                void* get() const;

                bool set(void* value);

     

            private:

                         unsigned int key;

            };

     

        }

     

    template <typename T>

    class vthread_specific_ptr : private noncopyable

    {

    public:

        vthread_specific_ptr() : m_tss(&thread_specific_ptr<T>::cleanup) { }

     

        T* get() const { return static_cast<T*>(m_tss.get()); }

        T* operator->() const { return get(); }

        T& operator*() const { return *get(); }

        T* release() { T* temp = get(); m_tss.set(0); return temp; }

        void reset(T* p=0) { T* cur = get(); if (cur == p) return; delete cur; m_tss.set(p); }

     

    private:

        static void cleanup(void* p) { delete static_cast<T*>(p); }

     

        mutable detail::vtss m_tss;

    };

     

    } // namespace boost

     

     

    #endif

     

      2.vtss.cpp文件

    #include <boost/thread/tss.hpp>

    #include <boost/thread/vtss.hpp>

    #include <boost/thread/mutex.hpp>

    #include <map>

    #include <set>

     

    namespace {

     

           class cleanup_info

           {

           public:

                  cleanup_info(void (*_cleanup)(void *)=0,void *_data=0)

                         :cleanup(_cleanup),data(_data){}

                  ~cleanup_info(){if(cleanup && data)cleanup(data);}

                  void reset(){data=0;}

                  void (*cleanup)(void *);

                  void *data;

           };

     

        typedef std::map<int, cleanup_info> cleanup_handlers;

     

           boost::thread_specific_ptr<cleanup_handlers> ptr_global;

     

           class tsskey

           {

                  tsskey();

           public:

                  static tsskey &instance();

                  unsigned int alloc();

                  void free(int key);

     

                  boost::mutex m_lock;

                  std::set<unsigned int> allkey;

                  unsigned int key;

           };

     

           tsskey::tsskey():key(0)

           {

           }

     

           tsskey &tsskey::instance()

           {

                  static tsskey tss;

                  return tss;

           }

     

           unsigned int tsskey::alloc()

           {

                  boost::mutex::scoped_lock lock(m_lock);

                  while(allkey.find(++key)!=allkey.end());

                  return key;

           }

     

           void tsskey::free(int key)

           {

                  boost::mutex::scoped_lock lock(m_lock);

                  allkey.erase(key);

           }

          

    }

     

    namespace boost {

     

           namespace detail {

     

                  vtss::vtss(void (*cleanup)(void*))

                         :m_cleanup(cleanup)

                  {

                         m_key=tsskey::instance().alloc();

                  }

     

                  vtss::~vtss()

                  {

                         tsskey::instance().free(m_key);

                  }

     

                  void* vtss::get() const

                  {

                         cleanup_handlers *p=ptr_global.get();

                         if(p)

                         {

                                cleanup_handlers::iterator it=p->find(m_key);

                                if(it!=p->end())

                                {

                                       return it->second.data;

                                }

                         }

                         return 0;

                  }

     

                  void vtss::set(void* value)

                  {

                         cleanup_handlers *p=ptr_global.get();

                         if(!p)

                         {

                                p=new cleanup_handlers;

                                ptr_global.reset(p);

                         }

     

                         if(value)

                         {

                                cleanup_info info(m_cleanup, value);

                                (*p)[m_key]=info;

                                info.reset();

                         }

                         else

                         {

                                p->erase(m_key);

                         }

                  }

     

           } // namespace detail

     

    } // namespace boost

     

       3Vtss.hpp文件放到<boost>/boost/thread/目录下,vtss.cpp文件放到<boost>/libs/thread/src。它们的用法和原先的pthread_specific_ptr的唯一区别是多了个“v”,也就是vpthread_specific_ptr。另外,还可以将vpthread_specific_ptrprivate noncopyable去掉,这时如果你的vpthread_specific_ptr在类对象里面,则该类对象也可以互相复制。

        其次的实现是读写锁,下回吧。


    最新回复(0)