青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

doing5552

記錄每日點滴,不枉人生一世

  C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
  73 Posts :: 0 Stories :: 94 Comments :: 0 Trackbacks

公告

常用鏈接

留言簿(24)

我參與的團隊

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 456167
  • 排名 - 49

最新隨筆

最新評論

閱讀排行榜

評論排行榜

昨天在上篇blog里描寫了如何把STL容器放到共享內(nèi)存里去,不過由于好久不寫blog,發(fā)覺詞匯組織能力差了很多,不少想寫的東西寫的很零散,今天剛好翻看自己的書簽,看到一篇挺老的文章,不過從共享內(nèi)存到STL容器講述得蠻全面,還提供了學(xué)習(xí)的實例,所以順便翻譯過來,并附上原文地址

共享內(nèi)存(shm)是當(dāng)前主流UNIX系統(tǒng)中的一種IPC方法,它允許多個進程把同一塊物理內(nèi)存段(segment)映射(map)到它們的地址空間中去。既然內(nèi)存段對于各自附著(attach)的進程是共享的,這些進程可以很方便的通過這塊共享內(nèi)存上的共有數(shù)據(jù)進行通信。因此,顧名思義,共享內(nèi)存就是進程之間共享的一組內(nèi)存段。當(dāng)一個進程附著到一塊共享內(nèi)存上后,它得到一個指向這塊共享內(nèi)存的指針;該進程可以像使用其他內(nèi)存一樣使用這塊共享內(nèi)存。當(dāng)然,由于這塊內(nèi)存同樣會被其他進程訪問或?qū)懭耄员仨氁⒁膺M程同步問題。

參考如下代碼,這是UNIX系統(tǒng)上使用共享內(nèi)存的一般方法(注:本文調(diào)用的是POSIX函數(shù)):

//Get shared memory id
            //shared memory key
            const key_t ipckey = 24568;
            //shared memory permission; can be
            //read and written by anybody
            const int perm = 0666;
            //shared memory segment size
            size_t shmSize = 4096;
            //Create shared memory if not
            //already created with specified
            //permission
            int shmId = shmget
            (ipckey,shmSize,IPC_CREAT|perm);
            if (shmId ==-1) {
            //Error
            }
             
            //Attach the shared memory segment
             
            void* shmPtr = shmat(shmId,NULL,0);
             
            struct commonData* dp =  (struct commonData*)shmPtr;
             
            //detach shared memory
            shmdt(shmPtr);

存放在共享內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)

當(dāng)保存數(shù)據(jù)到共享內(nèi)存中時需要留意,參考如下結(jié)構(gòu):

struct commonData {
            int sharedInt;
            float  sharedFloat;
            char* name;
            Struct CommonData* next;
            };

進程A把數(shù)據(jù)寫入共享內(nèi)存:

//Attach shared memory
            struct commonData* dp =
            (struct commonData*) shmat
            (shmId,NULL,0);
             
            dp->sharedInt = 5;
            .
            .
            dp->name = new char [20];
            strcpy(dp->name,"My Name");
             
            dp->next = new struct commonData();

稍后,進程B把數(shù)據(jù)讀出:

struct commonData* dp =
            (struct commonData*) shmat
            (shmId,NULL,0);
             
            //count = 5;
            int count = dp->sharedInt;
            //problem
            printf("name = [%s]\n",dp->name);
            dp = dp->next;  //problem

結(jié)構(gòu) commonData 的成員 name 和指向下一個結(jié)構(gòu)的 next 所指向的內(nèi)存分別從進程A的地址空間中的堆上分配,顯然 name 和 next 指向的內(nèi)存也只有進程A可以訪問。當(dāng)進程B訪問 dp->name 或者 dp->next 時候,由于它在訪問自己地址空間以外的內(nèi)存空間,所以這將是非法操作(memory violation),它無法正確得到 namenext 所指向的內(nèi)存。因此,所有的共享內(nèi)存中的指針必須同樣指向共享內(nèi)存中的地址。(這也是為什么包含虛函數(shù)繼承的C++類對象不能放到共享內(nèi)存中的原因——這是另外一個話題。注:因為虛函數(shù)的具體實現(xiàn)可能會在其他的內(nèi)存空間中)由于這些條件限制,放入共享內(nèi)存中的結(jié)構(gòu)應(yīng)該簡單簡單。(注:我覺得最好避免使用指針)

共享內(nèi)存中的STL容器

想像一下把STL容器,例如map, vector, list等等,放入共享內(nèi)存中,IPC一旦有了這些強大的通用數(shù)據(jù)結(jié)構(gòu)做輔助,無疑進程間通信的能力一下子強大了很多。我們沒必要再為共享內(nèi)存設(shè)計其他額外的數(shù)據(jù)結(jié)構(gòu),另外,STL的高度可擴展性將為IPC所驅(qū)使。STL容器被良好的封裝,默認情況下有它們自己的內(nèi)存管理方案。當(dāng)一個元素被插入到一個STL列表(list)中時,列表容器自動為其分配內(nèi)存,保存數(shù)據(jù)。考慮到要將STL容器放到共享內(nèi)存中,而容器卻自己在堆上分配內(nèi)存。一個最笨拙的辦法是在堆上構(gòu)造STL容器,然后把容器復(fù)制到共享內(nèi)存,并且確保所有容器的內(nèi)部分配的內(nèi)存指向共享內(nèi)存中的相應(yīng)區(qū)域,這基本是個不可能完成的任務(wù)。例如下邊進程A所做的事情:

//Attach to shared memory
            void* rp = (void*)shmat(shmId,NULL,0);
            //Construct the vector in shared
            //memory using placement new
            vector<int>* vpInA = new(rp) vector<int>*;
            //The vector is allocating internal data
            //from the heap in process A's address
            //space to hold the integer value
            (*vpInA)[0] = 22;

然后進程B希望從共享內(nèi)存中取出數(shù)據(jù):

vector<int>* vpInB =
            (vector<int>*) shmat(shmId,NULL,0);
             
            //problem - the vector contains internal 
            //pointers allocated in process A's address 
            //space and are invalid here 
            int i = *(vpInB)[0];

重用STL allocator

進一步考察STL容器,我們發(fā)現(xiàn)它的模板定義中有第二個默認參數(shù),也就是allocator 類,該類實際是一個內(nèi)存分配模型。默認的allocator是從堆上分配內(nèi)存(注:這就是STL容器的默認表現(xiàn),我們甚至可以改造它從一個網(wǎng)絡(luò)數(shù)據(jù)庫中分配空間,保存數(shù)據(jù))。下邊是 vector 類的一部分定義:

template<class T, class A = allocator<T> >
            class vector {
            //other stuff
            };

考慮如下聲明:

//User supplied allocator myAlloc
            vector<int,myAlloc<int> > alocV;

假設(shè) myAlloc 從共享內(nèi)存上分配內(nèi)存,則 alocV 將完全在共享內(nèi)存上被構(gòu)造,所以進程A可以如下:

//Attach to shared memory
            void* rp = (void*)shmat(shmId,NULL,0);
            //Construct the vector in shared memory
            //using placement new
            vector<int>* vpInA =
            new(rp) vector<int,myAlloc<int> >*;
            //The vector uses myAlloc<int> to allocate
            //memory for its internal data structure
            //from shared memory
            (*v)[0] = 22;

進程B可以如下讀出數(shù)據(jù):

vector<int>* vpInB =
            (vector<int,myAlloc<int> >*) shmat
            (shmId,NULL,0);
             
            //Okay since all of the vector is
            //in shared memory
            int i = *(vpInB)[0];

所有附著在共享內(nèi)存上的進程都可以安全的使用該vector。在這個例子中,該類的所有內(nèi)存都在共享內(nèi)存上分配,同時可以被其他的進程訪問。只要提供一個用戶自定義的allocator,任何STL容器都可以安全的放置到共享內(nèi)存上。

一個基于共享內(nèi)存的STL Allocator

清單 shared_allocator.hh 是一個STL Allocator的實現(xiàn),SharedAllocator 是一個模板類。而 Pool 類完成共享內(nèi)存的分配與回收。

template<class T>class SharedAllocator {
            private:
            Pool pool_;    // pool of elements of sizeof(T)
            public:
            typedef T value_type;
            typedef unsigned int  size_type;
            typedef ptrdiff_t difference_type;
            typedef T* pointer;
            typedef const T* const_pointer;
            typedef T& reference;
            typedef const T& const_reference;
            pointer address(reference r) const { return &r; }
            const_pointer address(const_reference r) const {return &r;}
            SharedAllocator() throw():pool_(sizeof(T)) {}
            template<class U> SharedAllocator
            (const SharedAllocator<U>& t) throw():
            pool_(sizeof(T)) {}
            ~SharedAllocator() throw() {};
            // space for n Ts
            pointer allocate(size_t n, const void* hint=0)
            {
            return(static_cast<pointer> (pool_.alloc(n)));
            }
            // deallocate n Ts, don't destroy
            void deallocate(pointer p,size_type n)
            {
            pool_.free((void*)p,n);
            return;
            }
            // initialize *p by val
            void construct(pointer p, const T& val) { new(p) T(val); }
            // destroy *p but don't deallocate
            void destroy(pointer p) { p->~T(); }
            size_type max_size() const throw()
            {
            pool_.maxSize();
            }
            template<class U>
            // in effect: typedef SharedAllocator<U> other
            struct rebind { typedef SharedAllocator<U> other; };
            };
             
            template<class T>bool operator==(const SharedAllocator<T>& a,
            const SharedAllocator<T>& b) throw()
            {
            return(a.pool_ == b.pool_);
            }
            template<class T>bool operator!=(const SharedAllocator<T>& a,
            const SharedAllocator<T>& b) throw()
            {
            return(!(a.pool_ == b.pool_));
            }

清單pool.hh是 Pool 類定義,其中靜態(tài)成員shm_ 是類型 shmPool,保證每個進程只有唯一的一個shmPool 實例。shmPool ctor 創(chuàng)建并附著所需大小的內(nèi)存到共享內(nèi)存上。共享內(nèi)存的參數(shù),比如 鍵值、段數(shù)目、段大小,都通過環(huán)境變量傳遞給 shmPool ctor。成員 segs_ 是共享段的數(shù)目,segSize_是每個共享段的大小,成員path_key_ 用來創(chuàng)建唯一的 ipckeyshmPool 為每個共享段創(chuàng)建一個信號量(semaphore)用于同步。shmPool 還在為每個共享段構(gòu)造了一個 Chunk 類,一個 Chunk代表一個共享段。每個共享段的標(biāo)識是shmId_, 信號量 semId_控制該段的訪問許可,一個指向 Link 結(jié)構(gòu)的指針表明 Chunk類的剩余列表。

class Pool {
            private:
            class shmPool {
            private:
            struct Container {
            containerMap* cont;
            };
            class Chunk {
            public:
            Chunk()
            Chunk(Chunk&);
            ~Chunk() {}
            void* alloc(size_t size);
            void free (void* p,size_t size);
            private:
            int shmId_;
            int semId_;
            int lock_()
            };
            int key_;
            char* path_;
            Chunk** chunks_;
            size_t segs_;
            size_t segSize_;
            Container* contPtr_;
            int contSemId_;
            public:
            shmPool();
            ~shmPool();
            size_t maxSize();
            void* alloc(size_t size);
            void free(void* p, size_t size);
            int shmPool::lockContainer()
            int unLockContainer()
            containerMap* getContainer()
            void shmPool::setContainer(containerMap* container)
            };
             
            private:
            static shmPool shm_;
            size_t elemSize_;
            public:
            Pool(size_t elemSize);
            ~Pool() {}
            size_t maxSize();
            void* alloc(size_t size);
            void free(void* p, size_t size);
            int lockContainer();
            int unLockContainer();
            containerMap* getContainer();
            void setContainer(containerMap* container);
            };
            inline bool operator==(const Pool& a,const Pool& b)
            {
            return(a.compare(b));
            }

把STL容器放入共享內(nèi)存

假設(shè)進程A在共享內(nèi)存中放入了數(shù)個容器,進程B如何找到這些容器呢?一個方法就是進程A把容器放在共享內(nèi)存中的確定地址上(fixed offsets),則進程B可以從該已知地址上獲取容器。另外一個改進點的辦法是,進程A先在共享內(nèi)存某塊確定地址上放置一個map容器,然后進程A再創(chuàng)建其他容器,然后給其取個名字和地址一并保存到這個map容器里。進程B知道如何獲取該保存了地址映射的map容器,然后同樣再根據(jù)名字取得其他容器的地址。清單container_factory.hh是一個容器工廠類。類Pool的方法setContainer把map容器放置在一個已知地址上,方法getContainer可以重新獲取這個map。該工廠的方法用來在共享內(nèi)存中創(chuàng)建、獲取和刪除容器。當(dāng)然,傳遞給容器工廠的容器需要以SharedAllocator作為allocator。

struct keyComp {
            bool operator()(const char* key1,const char* key2)
            {
            return(strcmp(key1,key2) < 0);
            }
            };
            class containerMap: public map<char*,void*,keyComp,SharedAllocator<char* > > {};
            class containerFactory {
            public:
            containerFactory():pool_(sizeof(containerMap)){}
            ~containerFactory() {}
            template<class Container> Container* createContainer
            (char* key,Container* c=NULL);
            template<class Container> Container* getContainer
            (char* key,Container* c=NULL);
            template<class Container> int removeContainer
            (char* key,Container* c=NULL);
            private:
            Pool pool_;
            int lock_();
            int unlock_();
            };

結(jié)論

本文描述的方案可以在共享內(nèi)存中創(chuàng)建STL容器,其中的一個缺陷是,在分配共享內(nèi)存之前,應(yīng)該保證共享內(nèi)存的總大小(segs_* segSize_)大于你要保存STL容器的最大長度,因為一旦類Pool 超出了共享內(nèi)存的,該類無法再分配新的共享內(nèi)存。

完整的源代碼可以從這里下載:www.cuj.com/code

參考文獻

  • Bjarne Stroustrup. The C++ Programming Language, Third Edition (Addison-Wesley, 1997).
  • Matthew H. Austern. Generic Programming and the STL: Using and
    Extending the C++ Standard Template Library (Addison-Wesley, 1999).

關(guān)于作者

Grum Ketema has Masters degrees in Electrical Engineering and Computer Science. With 17 years of experience in software development, he has been using C since 1985, C++ since 1988, and Java since 1997. He has worked at AT&T Bell Labs, TASC, Massachusetts Institute of Technology, SWIFT, BEA Systems, and Northrop.

posted on 2010-07-24 21:14 doing5552 閱讀(9038) 評論(6)  編輯 收藏 引用

Feedback

# re: [翻譯]把STL容器放入共享內(nèi)存 2012-03-01 16:42 弧光
博主,你好!,首先謝謝你翻譯并轉(zhuǎn)載這篇文章,本人受益匪淺。對于博文中有一段內(nèi)容不理解,不知道博主是否能解釋或者有實際的例子代碼?
以下部分為本人疑惑的地方:
把STL容器放入共享內(nèi)存
假設(shè)進程A在共享內(nèi)存中放入了數(shù)個容器,進程B如何找到這些容器呢?一個方法就是進程A把容器放在共享內(nèi)存中的確定地址上(fixed offsets),則進程B可以從該已知地址上獲取容器。另外一個改進點的辦法是,進程A先在共享內(nèi)存某塊確定地址上放置一個map容器,然后進程A再創(chuàng)建其他容器,然后給其取個名字和地址一并保存到這個map容器里。進程B知道如何獲取該保存了地址映射的map容器,然后同樣再根據(jù)名字取得其他容器的地址。清單container_factory.hh是一個容器工廠類。類Pool的方法setContainer把map容器放置在一個已知地址上,方法getContainer可以重新獲取這個map。該工廠的方法用來在共享內(nèi)存中創(chuàng)建、獲取和刪除容器。當(dāng)然,傳遞給容器工廠的容器需要以SharedAllocator作為allocator。

本人的聯(lián)系方式:
msn:duoduono2002@hotmail.com
qq:93320694
mail:hewg@szkingdom.com
以上任何方式均能聯(lián)系到本人,歡迎博主與其他看客來幫忙解決此疑問,謝謝!!!  回復(fù)  更多評論
  

# re: [翻譯]把STL容器放入共享內(nèi)存[未登錄] 2014-04-30 10:35 none
這篇文章最大的問題就在于它假定每個進程attach上這個共享內(nèi)存時得到的地址偏移量是相同的。但實際上往往是不同的,所以這篇文章中給出的方法是根本不能正常使用的。

當(dāng)兩個進程中同一塊共享內(nèi)存映射的地址偏移量不同的時候,任何放入共享內(nèi)存的指針都無法直接使用。像STL這種復(fù)雜的容器庫,里面大量用到了指針,如果不做偏移量調(diào)整的話幾乎可以肯定會出現(xiàn)嚴(yán)重問題。  回復(fù)  更多評論
  

# re: [翻譯]把STL容器放入共享內(nèi)存 2014-08-05 19:33 zzyoucan
今天也在看vector怎么存入共享內(nèi)存,不過boost可以,這個只是存入單個vector要是一個結(jié)構(gòu)體就不太好弄了,還是把vector換成數(shù)組吧。  回復(fù)  更多評論
  

# re: [翻譯]把STL容器放入共享內(nèi)存[未登錄] 2014-08-06 14:39 a
歪門邪道,正途是進行序列化操作  回復(fù)  更多評論
  

# re: [翻譯]把STL容器放入共享內(nèi)存 2016-01-15 11:50 ABC
@none
如果是同樣的映射 偏移怎么可能是不同的呢?如果 按你這種說法 共享內(nèi)存還能用? 你要如何才能算出里面的數(shù)據(jù)? 不說放map 這種了 你放字符串 放 struct 都沒法用。 別誤人 好不~!  回復(fù)  更多評論
  

# re: [翻譯]把STL容器放入共享內(nèi)存 2016-06-14 22:56 DDD
@ABC
人家是說的映射之后的基地址吧,共享內(nèi)存內(nèi)的 offset 是一樣的,但是在虛擬內(nèi)存中的地址很可能是不一樣的  回復(fù)  更多評論
  


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            狠色狠色综合久久| 久久久久一区| 国产日产精品一区二区三区四区的观看方式 | 黄色成人在线网站| 韩日视频一区| 在线免费观看日韩欧美| 在线观看国产成人av片| 亚洲国产日韩一区二区| 亚洲日本激情| 亚洲在线免费| 久久久久久久久久久久久女国产乱| 久久婷婷国产麻豆91天堂| 欧美3dxxxxhd| 99视频精品| 亚洲在线一区| 久久久久久久久久久一区| 免费短视频成人日韩| 欧美精品色一区二区三区| 国产精品久久久久一区二区三区| 欧美激情在线| 欧美视频二区36p| 国产美女精品人人做人人爽| 一区二区三区在线看| 亚洲乱码国产乱码精品精天堂 | 久久精品一区| 亚洲国产精品传媒在线观看| 欧美国产日韩精品| 亚洲神马久久| 久久资源av| 国产精品中文字幕欧美| 久久亚洲春色中文字幕| 欧美日韩精品三区| 国产一区二区三区四区在线观看 | 久久久久99精品国产片| 欧美日韩亚洲视频一区| 黑人操亚洲美女惩罚| 一本色道久久综合亚洲精品不卡| 久久精品毛片| 99国产精品99久久久久久粉嫩| 久久九九热免费视频| 欧美视频在线观看视频极品| 亚洲福利国产| 久久精品国产一区二区三区免费看 | 一区二区三区成人精品| 久久夜色精品亚洲噜噜国产mv| 欧美日韩一区二区视频在线观看| 亚洲第一福利视频| 久久电影一区| 亚洲天堂久久| 欧美精品在线一区| 亚洲激情国产精品| 蜜乳av另类精品一区二区| 亚洲字幕一区二区| 国产精品国产三级国产aⅴ无密码| 在线不卡中文字幕| 久久久青草青青国产亚洲免观| 亚洲天堂成人| 国产精品综合av一区二区国产馆| 一本高清dvd不卡在线观看| 亚洲国产欧美在线人成| 欧美+日本+国产+在线a∨观看| 亚洲激情第一区| 亚洲精品在线三区| 国产精品久久久久久久午夜片| 亚洲欧美日韩国产成人| 午夜精品三级视频福利| 国产自产精品| 欧美国产极速在线| 欧美极品在线播放| 亚洲一区二区三区乱码aⅴ| 亚洲先锋成人| 亚洲欧美在线免费观看| 亚洲欧美激情视频| 国产一区二区日韩精品欧美精品| 校园激情久久| 久久精品亚洲一区二区三区浴池| 国产欧美一区二区精品性| 欧美一区二区三区成人| 午夜精品久久久久久久99黑人| 国产一区二区日韩精品| 老司机精品福利视频| 久久综合亚州| 亚洲日本中文字幕| 亚洲精品中文字| 模特精品在线| 亚洲国产第一页| 国产欧美一区二区精品婷婷| 每日更新成人在线视频| 一区二区三区精密机械公司| 久久亚洲电影| 欧美精品激情| 久久国产乱子精品免费女| 亚洲免费观看高清完整版在线观看| 欧美一区二区三区免费在线看 | 蜜桃av噜噜一区| 国产精品日韩久久久久| 国产一区二区三区的电影 | 久久久久网址| 99国内精品久久| 嫩草影视亚洲| 在线观看日韩av先锋影音电影院 | 国产欧美日韩一区二区三区在线观看 | 在线观看成人小视频| 久久se精品一区精品二区| 亚洲乱码国产乱码精品精天堂| 久久久亚洲高清| 国产午夜精品全部视频播放 | 欧美黄色精品| 久久在线免费观看视频| 国产日韩欧美日韩| 亚洲女人小视频在线观看| 亚洲精选一区二区| 欧美精品日韩综合在线| 亚洲视频精选| 国产日韩成人精品| 这里只有精品视频| 欧美激情视频一区二区三区免费 | 欧美日韩一区成人| 一区二区三区国产在线观看| 欧美激情亚洲一区| 免费看的黄色欧美网站| 亚洲精品国产精品久久清纯直播| 亚洲电影专区| 欧美另类变人与禽xxxxx| 一区二区日韩精品| 久久爱另类一区二区小说| 欧美性做爰毛片| 欧美一区二区三区在线观看视频 | 美女网站久久| 欧美日韩精品一二三区| 亚洲国产精品激情在线观看| 欧美精品自拍| 性久久久久久久久| 久久黄色网页| 亚洲日本激情| 一区二区三区.www| 牛牛精品成人免费视频| 亚洲高清不卡在线| 国产精品毛片a∨一区二区三区|国| 欧美影院成年免费版| 久久这里有精品视频 | 日韩一级成人av| 99精品视频网| 狠狠久久亚洲欧美专区| 亚洲大片av| 一本久久综合亚洲鲁鲁五月天 | 亚洲手机在线| 欧美亚洲日本一区| 国产日韩在线看| 久久久久.com| 亚洲欧洲精品一区二区三区波多野1战4| 亚洲精品一区在线观看香蕉| 欧美日韩国内| 午夜精品久久久久久久蜜桃app| 久久久久一区| 亚洲精品在线免费观看视频| 欧美色精品天天在线观看视频| 亚洲一区二区三区在线视频| 久久久欧美精品| 亚洲免费观看高清在线观看 | 亚洲专区在线| 亚洲精品视频一区| 久久se精品一区二区| 一个色综合av| 久久久久成人精品免费播放动漫| 亚洲精品乱码久久久久久蜜桃91| 久久精品亚洲一区二区三区浴池| 亚洲另类自拍| 欧美一区视频在线| 夜夜嗨av一区二区三区四季av | 久久伊人一区二区| 欧美四级剧情无删版影片| 男人的天堂成人在线| 国产精品免费电影| 亚洲精品无人区| 久久久噜噜噜久久狠狠50岁| 国产精品美女久久| 日韩系列在线| 一道本一区二区| 欧美黄色大片网站| 亚洲精品影视在线观看| 国产视频精品免费播放| 亚洲一区二区三区四区五区午夜 | 99热这里只有精品8| 欧美一级欧美一级在线播放| 亚洲女同性videos| 欧美日韩精品国产| 亚洲影院色无极综合| 亚洲激情网站| 欧美高清视频在线观看| 欧美大片18| 亚洲人成网在线播放| 欧美xx69| 欧美一区亚洲二区| 亚洲免费网站| 国产麻豆一精品一av一免费| 亚洲欧美成人一区二区三区| 欧美一站二站| 国内精品模特av私拍在线观看| 国产精品免费观看在线|