• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 13, comments - 4, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            Imperfect C++ 讀書筆記(二)

            Posted on 2008-11-19 00:14 Batiliu 閱讀(508) 評論(0)  編輯 收藏 引用 所屬分類: 讀書筆記

            可移植的虛函數表

            C++并非一門合適的模塊——接口語言,為了支持ABI/OAB(Application Binary Interface/Objects Across Borders)需要付出相當程度的努力,并且使用者還必須受到嚴格的約束。下面介紹一種得到廣泛運用的跨邊界對象技術,如果你熟悉Win32 COM,肯定立馬心領神會。

             

            接口代碼:

            // Interface.h
            //
            struct IObject;
             
            struct IObjectVTable
            {
                void (*SetName)(struct IObject * obj, char const * s);
                char const * (*GetName)(struct IObject const * obj);
            };
             
            struct IObject
            {
                struct IObjectVTable * const vtable;
            #ifdef __cplusplus
            protected:
                IObject(struct IObjectVTable * vt)
                    : vtable(vt)
                {}
                ~IObject()
                {}
            public:
                inline void SetName(char const * s)
                {
                    assert(NULL != vtable);
                    vtable->SetName(this, s);
                }
                inline char const * GetName() const
                {
                    assert(NULL != vtable);
                    return vtable->GetName(this);
                }
            private:
                IObject(IObject const & rhs);
                IObject & operator=(IObject const & rhs);
            #endif    /* __cplusplus */
            };
             
            extern "C" IObject * createObject();
            extern "C" void destroyObject(IObject *);

             

            服務端代碼:

            // Server.cpp
            //
            class Object : public IObject
            {
            public:
                virtual void SetName(char const * s)
                {
                    m_name = s;
                }
                virtual char const * GetName() const
                {
                    return m_name.c_str();
                }
            #ifndef POAB_COMPILER_HAS_COMPATIBLE_VTABLES
            public:
                Object()
                    : IObject(GetVTable())
                {}
                Object(Object const & rhs)
                    : IObject(GetVTable())
                    , m_name(rhs.m_name)
                {}
            private:
                static void SetName_(IObject * this_, char const * s)
                {
                    static_cast<Object*>(this_)->SetName(s);
                }
                static char const * GetName_(IObject const * this_)
                {
                    return static_cast<Object const *>(this_)->GetName();
                }
                static IObjectVTable * GetVTable()
                {
                    static IObjectVTable s_vt = MakeVTable();
                    return &s_vt;
                }
                static IObjectVTable MakeVTable()
                {
                    IObjectVTable vt = { SetName_, GetName_ };
                    return vt;
                }
            #endif    /* !POAB_COMPILER_HAS_COMPATIBLE_VTABLES */
            private:
                std::string m_name;
            };

             

            客戶端代碼:

            // Client.cpp
            //
            int _tmain(int argc, _TCHAR* argv[])
            {
                IObject * pObj = createObject();
             
                pObj->SetName("Matthew Wilson");
             
                std::cout << "name: " << pObj->GetName() << std::endl;
             
                destroyObject(pObj);
             
                return 0;
            }

             

            synchronized關鍵字

            Java中有synchronized關鍵字,.NET中有lock關鍵字,它們可以被用于守護臨界區。而C++標準對線程幾乎只字未提,自然也沒有相關設施。而然借助一點點宏,我們就能輕松實現同樣的效果:(lock_scope請參考筆記(一)中的域守衛類)

            #define SYNCHRONIZED_BEGIN(T, v) \
                { \
                    lock_scope<T> __lock__(v);
            #define SYNCHROIZED_END() \
                }

             

            如果你和我一樣不喜歡SYNCHROIZE_END()部分,畢竟和synchronized或lock比起來似乎不那么優雅,那么可以用點小技巧,像這樣定義宏:

            #define synchronized(T, v) \
                for (synchronized_lock<lock_scope<T> > __lock__(v); \
                    __lock__; __lock__.end_loop())
             
            template<typename T>
            struct synchronized_lock : public T
            {
            public:
                template<typename U>
                synchronized_lock(U & u)
                    : T(u)
                    , m_bEnded(false)
                {}
                operator bool () const
                {
                    return !m_bEnded;
                }
                void end_loop()
                {
                    m_bEnded = true;
                }
            private:
                bool m_bEnded;
            };

            客戶代碼:

            synchronized(Object, obj)
            {
                ...    // 臨界區代碼
            }
             
                ...    // 非臨界區代碼
             
            synchronized(Object, obj)
            {
                ...    // 臨界區代碼
            }

             

            上述代碼,熟悉JAVA的朋友是不是很親切?不過還是有個小小的遺憾,那就是對象的類型不能被自動推導出來,導致我們必須手工提供兩個參數。

            這里還有個問題要注意,如果同一個作用域中出現了兩個同步段,某些老式編譯器(如大名鼎鼎的VC6.0)對for循環處理的不那么“標準”,就會報出“重新定義__lock__”的錯誤。所以作者對此提供了一個可移植的解決方案,來確保每個“__lock__”都是不一樣的:

            #define concat__(x, y) x ## y
            #define concat_(x, y) concat__(x, y)    // 用兩層宏來取__LINE__的實際值
            #define synchronized(T, v) \
                for (synchronized_lock<lock_scope<T> > concat_(__lock__,__LINE__)(v); \
                    concat_(__lock__,__LINE__); concat_(__lock__,__LINE__).end_loop())

            但是,作者似乎忘了,某些老式編譯器(如VC6.0)對循環變量的釋放,會延遲到整個作用域結束時,而不是臨界代碼段的右括號處。所以該解決方案是錯誤的!

             

            局部靜態對象

            函數局部靜態對象的初始化存在的固有的競爭條件是非常重要的問題。因此不能被忽略。然而,它同時也是非常罕見的情況。我們可以利用其罕見性,給出一個極其優雅的解決方案,該解決方案基于自旋互斥體。自旋互斥體本身依賴于原子操作,它的開銷是非常低的。

            class spin_mutex
            {
            public:
                explicit spin_mutex(int * p = NULL)
                    : m_spinCount((NULL != p) ? p : &m_internalCount)
                    , m_internalCount(0)
                {}
                void lock()
                {
                    for (; 0 != atomic_write(m_spinCount, 1); sched_yield())
                    {}    // PTHREAD函數seched_yield()將執行機會讓給其他線程
                }
                void unlock()
                {
                    atomic_set(m_spinCount, 0);
                }
            private:
                int * m_spinCount;
                int m_internalCount;
            private:
                spin_mutex(spin_mutex const & rhs);
                spin_mutex & operator=(spin_mutex const & rhs);
            };
             
            Local & GetLocal()
            {
                static int guard;         // 在加載期被初始化為0
                spin_mutex smx(&guard);             // 對guard進行自旋
                lock_scope<spin_mutex> lock(smx);   // 使用smx來加鎖
             
                static Local local;
                return local;
            }
            2019久久久高清456| 久久综合丁香激情久久| 日韩va亚洲va欧美va久久| 人妻中文久久久久| 亚洲人成网亚洲欧洲无码久久 | 精品永久久福利一区二区| 久久99热只有频精品8| 久久人人超碰精品CAOPOREN| 亚洲精品乱码久久久久久按摩| 久久这里只有精品首页| 久久强奷乱码老熟女网站| 久久久久久久综合日本亚洲| 一级a性色生活片久久无| 亚洲国产精品久久久久久| 久久久久久精品成人免费图片| 久久久久成人精品无码中文字幕| 久久久久亚洲av成人无码电影| 69国产成人综合久久精品| 热综合一本伊人久久精品| 久久精品国产91久久麻豆自制| 久久受www免费人成_看片中文| 丰满少妇人妻久久久久久4| 亚洲精品国精品久久99热一| 一本一道久久a久久精品综合| 久久WWW免费人成—看片| 国产精品18久久久久久vr | 欧美黑人激情性久久| 久久影院亚洲一区| 久久嫩草影院免费看夜色| 精品久久久久一区二区三区| 蜜桃麻豆www久久| 91精品国产综合久久香蕉 | 精品无码久久久久国产动漫3d| 久久国产成人| 久久久人妻精品无码一区| 久久精品亚洲福利| 久久久久久亚洲精品无码| 国产一区二区三精品久久久无广告| 久久精品国产亚洲欧美| 91精品国产高清久久久久久国产嫩草| 99精品国产在热久久|