久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

下篇 | 说说无锁(Lock-Free)编程那些事(下)

發布時間:2024/2/28 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 下篇 | 说说无锁(Lock-Free)编程那些事(下) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.




6 內存屏障(Memory Barriers)

6.1 What Memory Barriers?
內存屏障,也稱內存柵欄,內存柵障,屏障指令等,是一類同步屏障指令,是CPU或編譯器在對內存隨機訪問的操作中的一個同步點,使得此點之前的所有讀寫操作都執行后才可以開始執行此點之后的操作。大多數現代計算機為了提高性能而采取亂序執行,這使得內存屏障成為必須。語義上,內存屏障之前的所有寫操作都要寫入內存;內存屏障之后的讀操作都可以獲得同步屏障之前的寫操作的結果。因此,對于敏感的程序塊,寫操作之后、讀操作之前可以插入內存屏障。


通常情況下,我們希望我們所編寫的程序代碼能"所見即所得",即程序邏輯滿足程序的順序性(滿足program order),然而,很遺憾,我們的程序邏輯("所見")和最后的執行結果("所得")隔著:
```
1. 編譯器
2. CPU取指執行
```
1.?編譯器將符合人類思考的邏輯(程序代碼)翻譯成了符合CPU運算規則的匯編指令,編譯器了解底層CPU的思維模式,因此,它可以在將程序翻譯成匯編的時候進行優化(例如內存訪問指令的重新排序),讓產出的匯編指令在CPU上運行的時候更快。然而,這種優化產出的結果未必符合程序員原始的邏輯,因此,作為程序員,必須有能力了解編譯器的行為,并在通過內嵌在程序代碼中的memory barrier來指導編譯器的優化行為(這種memory barrier又叫做優化屏障,Optimization barrier),讓編譯器產出即高效,又邏輯正確的代碼。


2.?CPU的核心思想就是取指執行,對于in-order的單核CPU,并且沒有cache,匯編指令的取指和執行是嚴格按照順序進行的,也就是說,匯編指令就是所見即所得的,匯編指令的邏輯嚴格的被CPU執行。然而,隨著計算機系統越來越復雜(多核、cache、superscalar、out-of-order),使用匯編指令這樣貼近處理器的語言也無法保證其被CPU執行的結果的一致性,從而需要程序員告知CPU如何保證邏輯正確。

綜上所述,memory barrier是一種保證內存訪問順序的一種方法,讓系統中的HW block(各個cpu、DMA controler、device等)對內存有一致性的視角。


通過上面介紹,我們知道我們所編寫的代碼會根據一定規則在與內存的交互過程中發生亂序。內存執行順序的變化在編譯器(編譯期間)和cpu(運行期間)中都會發生,其目的都是為了讓代碼運行的更快。就算是為了性能而亂序,但是亂序總有個度吧(總不能將指針的初始化的代碼亂序在使用指針的代碼之后吧,這樣誰還敢寫代碼)。編譯器開發者和cpu廠商都遵守著內存亂序的基本原則,簡單歸納如下:
```
不能改變單線程程序的執行行為 -- 但線程程序總是滿足Program Order(所見即所得)
```
在此原則指導下,寫單線程代碼的程序員不需要關心內存亂序的問題。在多線程編程中,由于使用互斥量,信號量和事件都在設計的時候都阻止了它們調用點中的內存亂序(已經隱式包含各種memery barrier),內存亂序的問題同樣不需要考慮了。只有當使用無鎖(lock-free)技術時–內存在線程間共享而沒有任何的互斥量,內存亂序的效果才會顯露無疑,這樣我們才需要考慮在合適的地方加入合適的memery barrier。


6.1.1 編譯期亂序
考慮下面一段代碼:
```
int Value = 0;
int IsPublished = 0;
?
void sendValue(int x)
{
????Value = x;
????IsPublished = 1;
}

int tryRecvValue()
{
????if (IsPublished)
????{
????????return Value;
????}
????return -1;??// or some other value to mean not yet received
}
```
在出現編譯期亂序的時候,sendValue可能變成如下:
```
void sendValue(int x)
{
????IsPublished = 1;
????Value = x;
}
```
對于但線程而言,這樣的亂序是不會有影響的,因為sendValue(10)調用后,IsPublished == 1; Value == 10;這時調用tryRecvValue()就會得到10和亂序前是一樣的結果。但是對于多線程,線程1調用sendValue(10), 線程2調用tryRecvValue(),當線程1執行完IsPublished = 1;的時候,線程2調用tryRecvValue()就會得到Value的初始默認值0,這和程序原本邏輯違背,于是我們必須加上編譯器的barrier來防止編譯器的亂序優化:
```
#define COMPILER_BARRIER() asm volatile("" ::: "memory")

int Value;
int IsPublished = 0;

void sendValue(int x)
{
????Value = x;
????COMPILER_BARRIER();??????????// prevent reordering of stores
????IsPublished = 1;
}

int tryRecvValue()
{
????if (IsPublished)
????{
????????COMPILER_BARRIER();??????// prevent reordering of loads
????????return Value;
????}
????return -1;??// or some other value to mean not yet received
}
```
下面也是一個編譯器亂序的例子(在Gcc4.8.5下 gcc -O2 -c -S compile_reordering.cpp):

????

可以看出,在開啟-o2編譯器優化選項時,內存會發生亂序,在寫變量A之前會先寫變量B。


6.1.2 運行期亂序
下面看一個運行期CPU亂序的例子:


可以看出在22W多次迭代后檢測到一次亂序,亂序間隔在搖擺不定。

6.2 Why Memory Barriers?

6.2.1 現代處理器cache架構
通過上面,我們知道存在兩種類型的Memory Barriers:編譯器的Memory Barrier、處理器的Memory Barrier。對于編譯器的Memory Barrier比較好理解,就是防止編譯器為了優化而將代碼執行調整亂序。而處理器的Memory Barrier是防止CPU怎樣的亂序呢?CPU的內存亂序是怎么來的?
亂序會有問題本質上是讀到了老的數據,或者是一部分讀到新的一部分讀到老的數據,例如:上面的例子中,已經讀到了IsPublished的新值,卻還是讀到了Value老的值,從而引起問題。這種數據不一致怎么來的呢?相信這個時候大家腦海里已經浮現出一個詞了:Cache。


首先我們來看看現代處理器基本的cache架構


現代處理器為了彌補內存速度低下的缺陷,引入Cache來提高處理器訪問程序和數據的速度,Cache作為連接內核和內存的橋梁,極大提升了程序的運行速度。為什么處理器內部加一個速度快,容量小的cache就能提速呢?這里基于程序的兩個特性:時間的局部性(Temporal locality)和空間的局部性(Spatial)
```
[1] 時間的局部性(Temporal locality):如果某個數據被訪問了,那么不久的將來它很有可能被再次訪問到。典型的例子就是循環,循環的代碼被處理器重復執行,將循環代碼放在Cache中,那么只是在第一次的時候需要耗時較長去內存取,以后這些代碼都能被內核從cache中快速訪問到。
[2] 空間的局部性(Spatial):如果某個數據被訪問了,那么它相臨的數據很可能很快被訪問到。典型的例子就是數組,數組中的元素常常安裝順序依次被程序訪問。
```
現代處理器一般是多個核心Core,每個Core在并發執行不同的代碼和訪問不同的數據,為了隔離影響,每個core都會有自己私有的cache(如圖的L1和L2),同時也在容量和存儲速度上進行一個平衡(容量也大存儲速度越慢,速度:L1>L2>L3, 容量:L3>L2>L1),于是就出現圖中的層次化管理。Cache的層次化必然帶來一個cache一致性的問題:


如圖的例子,變量X(初始值是3)被cache在Core 0和Core 1的私有cache中,這時core 0將X修改成5,如果core 1不知道X已經被修改了,繼續使用cache中的舊值,那么可能會導致嚴重的問題,這就是Cache的不一致導致的。為了保證Cache的一致性,處理器提供兩個保證Cache一致性的底層操作:Write Invalidate和Write Update。
```
Write Invalidate(置無效):當一個CPU Core修改了一份數據X,那么它需要通知其他core將他們的cache中的X設置為無效(invalid)(如果cache中有的話),如下圖
```

```
Write Update(寫更新):當一個CPU Core修改了一份數據X,那么它需要通知其他core將他們的cache中的X更新到最新值(如果cache中有的話),如下圖
```


Write Invalidate和Write Update的比較:Write Invalidate是一種更為簡單和輕量的實現方式,它不需要立刻將數據更新到存儲中(這時一個耗時過程),如果后續Core 0繼續需要修改X而Core 1和Core 2又不再使用數據X了,那么這個Update過程就有點做了無用功,而采用write invalidate就更為輕量和有效。不過,由于valid標志是對應一個Cache line的,將valid標志設置為invalid后,這個cache line的其他本來有效的數據也不能被使用了,如果處理不好容易出現前面提到的False sharing(偽共享)和Cache pingpong問題。


6.2.2 cache一致性協議MESI
由于Write Invalidate比較簡單和輕量,大多數現代處理器都采用Write Invalidate策略,基于Write Invalidate處理器會有一套完整的協議來保證Cache的一致性,比較經典的當屬MESI協議,奔騰處理器采用它,很多其他處理器都是采用它的一個小變種。


每個核的Cache中的每個Cache Line都有2個標志位:dirty標志和valid標志位,兩個標志位分別描述了Cache和Memory間的數據關系(數據是否有效,數據是否被修改),而在多核處理器中,多個核會共享一些數據,MESI協議就包含了描述共享的狀態。


這樣在MESI協議中,每個Cache line都有4個狀態,可用2個bit來表示(也就是,每個cache line除了物理地址和具體的數據之外,還有一個2-bit的tag來標識該cacheline的4種不同的狀態):
```
[1] M(Modified): cache line數據有效,但是數據被修改過了,本Cache中的數據是最新的,內存的數據是老的,需要在適當時候將Cache數據寫回內存。因此,處于modified狀態的cacheline也可以說是被該CPU獨占。而又因為只有該CPU的cache保存了最新的數據(最終的memory中都沒有更新),所以,該cache需要對該數據負責到底。例如根據請求,該cache將數據及其控制權傳遞到其他cache中,或者cache需要負責將數據寫回到memory中,而這些操作都需要在reuse該cache line之前完成。

[2] E(Exclusive):cache line數據有效,并且cache和memory中的數據是一致的,同時數據只在本cache中有效。exclusive狀態和modified狀態非常類似,唯一的區別是對應CPU還沒有修改cacheline中的數據,也正因為還沒有修改數據,因此memory中對應的data也是最新的。在exclusive狀態下,cpu也可以不通知其他CPU cache而直接對cacheline進行操作,因此,exclusive狀態也可以被認為是被該CPU獨占。由于memory中的數據和cacheline中的數據都是最新的,因此,cpu不需對exclusive狀態的cacheline執行寫回的操作或者將數據以及歸屬權轉交其他cpu cache,而直接reuse該cacheline(將cacheine中的數據丟棄,用作他用)。

[3] S(Shared):cache line的數據有效,并且cache和memory中的數據是一致的,同時該數據在多個cpu cache中也是有效的。和exclusive狀態類似,處于share狀態的cacheline對應的memory中的數據也是最新的,因此,cpu也可以直接丟棄cacheline中的數據而不必將其轉交給其他CPU cache或者寫回到memory中。

[4] I(Invalid):本cache line的數據已經是無效的。處于invalid狀態的cacheline是空的,沒有數據。當新的數據要進入cache的時候,優選狀態是invalid的cacheline,之所以如此是因為如果選中其他狀態的cacheline,則說明需要替換cacheline數據,而未來如果再次訪問這個被替換掉的cacheline數據的時候將遇到開銷非常大的cache miss。
```
在MESI協議中,每個CPU都會監聽總線(bus)上的其他CPU對每個Cache line的所有操作,因此該協議也稱為監聽(snoop)協議,監聽協議比較簡單,被多少處理器使用,不過監聽協議的溝通成本比較高。有另外一種協議叫目錄協議,他采用集中管理的方式,將cache共享的信息集中在一起,類似一個目錄,只有共享的Cache line才會交互數據,這種協議溝通成本就大大減少了。在基于snoop的處理器中,所有的CPU都是在一個共享的總線上,多個CPU之間需要相互通信以保證Cache line在M、E、S、I四個狀態間正確的轉換,從而保證數據的一致性。通常情況下,CPU需要以下幾個通信message即可:
```
[1] Read消息:read message用來獲取指定物理地址上的cacheline數據。

[2] Read Response消息:該消息攜帶了read message請求的數據。read response可能來自memory,也可能來自其他的cache。例如:如果一個cache有read message請求的數據并且該cacheline的狀態是modified,那么該cache必須以read response回應這個read message,因為該cache中保存了最新的數據。

[3] Invalidate消息:該命令用來將其他cpu cache中的數據設定為無效。該命令攜帶物理地址的參數,其他CPU cache在收到該命令后,必須進行匹配,發現自己的cacheline中有該物理地址的數據,那么就將其移除并用Invalidate Acknowledge回應。

[4] Invalidate Acknowledge消息: 收到invalidate message的cpu cache,在移除了其cache line中的特定數據之后,必須發送invalidate acknowledge消息。

[5] Read Invalidate消息: 該message中也包括了物理地址這個參數,以便說明其想要讀取哪一個cacheline數據。此外,該message還同時有invalidate message的功效,即其他的cache在收到該命令后,移除自己cacheline中的數據。因此,Read Invalidate message實際上就是read + invalidate。發送Read Invalidate之后,cache期望收到一個read response以及多個invalidate acknowledge。

[6] Writeback消息: 該message包括兩個參數,一個是地址,另外一個是寫回的數據。該消息用在modified狀態的cacheline被驅逐出境(給其他數據騰出地方)的時候發出,該命名用來將最新的數據寫回到memory(或者其他的CPU cache中)。
```
根據protocol message的發送和接收情況,cacheline會在“modified”, “exclusive”, “shared”, 和 “invalid”這四個狀態之間遷移,具體如下圖所示:

對上圖中的狀態遷移解釋如下:
```
[a] Transition (a):cache可以通過writeback transaction將一個cacheline的數據寫回到memory中(或者下一級cache中),這時候,該cacheline的狀態從Modified遷移到Exclusive狀態。對于cpu而言,cacheline中的數據仍然是最新的,而且是該cpu獨占的,因此可以不通知其他cpu cache而直接修改之。

[b] Transition (b):在Exclusive狀態下,cpu可以直接將數據寫入cacheline,不需要其他操作。相應的,該cacheline狀態從Exclusive狀態遷移到Modified狀態。這個狀態遷移過程不涉及bus上的Transaction(即無需MESI Protocol Messages的交互)。

[c] Transition (c):CPU 在總線上收到一個read invalidate的請求,同時,該請求是針對一個處于modified狀態的cacheline,在這種情況下,CPU必須該cacheline狀態設置為無效,并且用read response”和“invalidate acknowledge來回應收到的read invalidate的請求,完成整個bus transaction。一旦完成這個transaction,數據被送往其他cpu cache中,本地的copy已經不存在了。

[d] Transition (d):CPU需要執行一個原子的readmodify-write操作,并且其cache中沒有緩存數據,這時候,CPU就會在總線上發送一個read invalidate用來請求數據,同時想獨自霸占對該數據的所有權。該CPU的cache可以通過read response獲取數據并加載cacheline,同時,為了確保其獨占的權利,必須收集所有其他cpu發來的invalidate acknowledge之后(其他cpu沒有local copy),完成整個bus transaction。

[e] Transition (e):CPU需要執行一個原子的readmodify-write操作,并且其local cache中有read only的緩存數據(cacheline處于shared狀態),這時候,CPU就會在總線上發送一個invalidate請求其他cpu清空自己的local copy,以便完成其獨自霸占對該數據的所有權的夢想。同樣的,該cpu必須收集所有其他cpu發來的invalidate acknowledge之后,才算完成整個bus transaction。

[f] Transition (f):在本cpu獨自享受獨占數據的時候,其他的cpu發起read請求,希望獲取數據,這時候,本cpu必須以其local cacheline的數據回應,并以read response回應之前總線上的read請求。這時候,本cpu失去了獨占權,該cacheline狀態從Modified狀態變成shared狀態(有可能也會進行寫回的動作)。

[g] Transition (g):這個遷移和f類似,只不過開始cacheline的狀態是exclusive,cacheline和memory的數據都是最新的,不存在寫回的問題。總線上的操作也是在收到read請求之后,以read response回應。

[h] Transition (h):如果cpu認為自己很快就會啟動對處于shared狀態的cacheline進行write操作,因此想提前先霸占上該數據。因此,該cpu會發送invalidate敦促其他cpu清空自己的local copy,當收到全部其他cpu的invalidate acknowledge之后,transaction完成,本cpu上對應的cacheline從shared狀態切換exclusive狀態。還有另外一種方法也可以完成這個狀態切換:當所有其他的cpu對其local copy的cacheline進行寫回操作,同時將cacheline中的數據設為無效(主要是為了為新的數據騰些地方),這時候,本cpu坐享其成,直接獲得了對該數據的獨占權。

[i] Transition (i):其他的CPU進行一個原子的read-modify-write操作,但是,數據在本cpu的cacheline中,因此,其他的那個CPU會發送read invalidate,請求對該數據以及獨占權。本cpu回送read response”和“invalidate acknowledge”,一方面把數據轉移到其他cpu的cache中,另外一方面,清空自己的cacheline。

[j] Transition (j):cpu想要進行write的操作但是數據不在local cache中,因此,該cpu首先發送了read invalidate啟動了一次總線transaction。在收到read response回應拿到數據,并且收集所有其他cpu發來的invalidate acknowledge之后(確保其他cpu沒有local copy),完成整個bus transaction。當write操作完成之后,該cacheline的狀態會從Exclusive狀態遷移到Modified狀態。

[k] Transition (k):本CPU執行讀操作,發現local cache沒有數據,因此通過read發起一次bus transaction,來自其他的cpu local cache或者memory會通過read response回應,從而將該cacheline從Invalid狀態遷移到shared狀態。

[l] Transition (l):當cacheline處于shared狀態的時候,說明在多個cpu的local cache中存在副本,因此,這些cacheline中的數據都是read only的,一旦其中一個cpu想要執行數據寫入的動作,必須先通過invalidate獲取該數據的獨占權,而其他的CPU會以invalidate acknowledge回應,清空數據并將其cacheline從shared狀態修改成invalid狀態。
```
下面通過幾個例子,說明一下MESI協議是怎么工作的。CPU執行序列如下:


第一列是操作序列號,第二列是執行操作的CPU,第三列是具體執行哪一種操作,第四列描述了各個cpu local cache中的cacheline的狀態(用meory address/狀態表示),最后一列描述了內存在0地址和8地址的數據內容的狀態:V表示是最新的,和cpu cache一致,I表示不是最新的內容,最新的內容保存在cpu cache中。
```
[1] sequence 0:初始狀態下,內存地址0和8保存了最新的數據,而4個CPU的cache line都是invalid(沒cache任何數據或cache的數據都是過期無效的)。

[2] sequence 1:CPU 0對內存地址0執行load操作,這樣內存地址0的數據被加載到CPU 0的cache line中,CPU 0的cache line從Invalid狀態切換到Share狀態(這個時候,CPU 0的cache line和內存地址0都是相同的最新數據)。

[3] sequence 2:CPU 3也對內存地址0執行load操作,這樣內存地址0的數據被加載到CPU 3的cache line中,CPU 3的cache line從Invalid狀態切換到Share狀態(這個時候,CPU 0、CPU 3的cache line和內存地址0都是相同的最新數據)。

[4] sequence 3:CPU 0執行對內存地址8的load操作,(內存地址0和8共用一個cache line set)由于cache line已經存放了內存地址0的數據,這個時候,CPU 0需要將cache line的數據清理掉(Invalidation)以便騰出空間存放內存地址8的數據。由于,當前cache line的狀態是Share,CPU 0不需要通知其他CPU,CPU 0在Invalidation cache line的數據后,就加載內存地址8的數據到cache line中,并將cache line狀態改成Share。

[5] sequence 4:CPU 2對內存地址0執行load操作,由于CPU 2知道程序隨后會修改該值,它需要獨占該數據,因此CPU 2向總線發送了read invalidate命令,一方面獲取該數據(自己的local cache中沒有地址0的數據),另外,CPU 2想獨占該數據(因為隨后要write)。這個操作導致CPU 3的cacheline遷移到invalid狀態。當然,這時候,memory仍然是最新的有效數據。

[6] sequence 5:CPU 2對內存地址0執行Store操作,由于CPU 2的cache line是Exclusive狀態(對內存地址0的數據是獨占狀態的),于是CPU 2可以直接將新的值寫入cache line覆蓋老值,cache line狀態轉換成Modified狀態。(這個時候,內存地址0中的數據已經是Invalid的,其他CPU如果想load內存地址0的數據,不能直接從內存地址0加載數據了,需要嗅探(snoop)的方式從CPU 2的local cache中獲取。

[7] sequence 6:CPU 1對內存地址0執行一個原子加操作。這時候CPU 1會發出read invalidate命令,將地址0的數據從CPU 2的cache line中嗅探得到,同時通過invalidate其他CPU local cache的內容而獲得獨占性的數據訪問權。這時候,CPU 2中的cache line狀態變成invalid狀態,而CPU 1的cache line將從invalid狀態遷移到modified狀態。

[8] sequence 7:CPU 1對內存地址8執行load操作。由于cache line已經存放了內存地址0的數據,并且該狀態是modified的,CPU 1需要將cache line的數據寫回地址0,于是執行write back操作將地址0的數據寫回到memory(這個時候,內存地址0中的數據從Invalid變成有效的)。接著,CPU 1發出read命令,從CPU 0中得到內存地址8的數據,并寫入自己的cache line,cache line狀態轉換成Share。
```
通過上面的例子,我們發現,對于某些特定地址的數據(在一個cache line中)重復的進行讀寫,這種結構可以獲得很好的性能(例如,在sequence 5,CPU 2反復對內存地址0進行store操作將獲得很好的性能,因為,每次store操作,CPU 2僅僅需要將新值寫入自己的local cache即可),不過,對于第一次寫,其性能非常差,如圖:


cpu 0發起一次對某個地址的寫操作,但是local cache沒有數據,該數據在CPU 1的local cache中,因此,為了完成寫操作,CPU 0發出invalidate的命令,invalidate其他CPU的cache數據。只有完成了這些總線上的transaction之后,CPU 0才能正在發起寫的操作,這是一個漫長的等待過程。


6.2.3 Store Buffer
對于CPU 0來說,這樣的漫長等待顯得有點沒必要,因為,CPU 1中的cache line保存有什么樣子的數據,其實都沒有意義,這個值都會被CPU 0新寫入的值覆蓋的。為了給CPU 0提速,需要將這種同步阻塞等待,變成異步處理。于是,硬件工程師,修改CPU架構,在CPU和cache之間增加store buffer這個HW block,如下圖所示:


一旦增加了store buffer,那么cpu 0無需等待其他CPU的相應,只需要將要修改的內容放入store buffer,然后繼續執行就OK了。當cache line完成了bus transaction,并更新了cache line的狀態后,要修改的數據將從store buffer進入cache line。引入了store buff,帶來了一些復雜性,一不小心,會帶來本地數據不一致的問題。我們先看看下面的代碼:
```
1 a = 1;?
2 b = a + 1;?
3 assert(b == 2);
a和b都是初始化為0,并且變量a在CPU 1的cache line中,變量b在CPU 0的cacheline中。
```
如果cpu執行上述代碼,那么第三行的assert不應該失敗,不過,如果CPU設計者使用上圖中的那個非常簡單的store buffer結構,那么你應該會遇到“驚喜”(assert失敗了)。具體的執行序列過程如下:
```
[1] CPU 0執行a=1的賦值操作, CPU 0遇到cache miss
[2] CPU 0發送read invalidate消息以便從CPU 1那里獲得數據,并invalid其他cpu保存a數據的local cache line。
[3] 由于store buff的存在,CPU 0把要寫入的數據“1”放入store buffer
[4] CPU 1收到read invalidate后回應,把本地cache line的數據發送給CPU 0并清空本地cache中a的數據。
[5] CPU 0執行b = a + 1
[6] CPU 0 收到來自CPU 1的數據,該數據是“0”
[7] CPU 0從cache line中加載a,獲得0值
[8] CPU 0將store buffer中的值寫入cache line,這時候cache中的a值是“1”
[9] CPU 0執行a+1,得到1并將該值寫入b
[10] CPU 0 executes assert(b == 2), which fails. OMG,你期望b等于2,但是實際上b等于了1
```
導致這個問題的根本原因是我們有兩個a值,一個在cache line中,一個在store buffer中。store buffer的引入,違反了每個CPU按照其視角來觀察自己的行為的時候必須是符合program order的原則。一旦違背這個原則,對軟件工程師而言就是災難。還好,有”好心“的硬件工程師幫助我們,修改了CPU的設計如下:


這種設計叫做store forwarding,當CPU執行load操作的時候,不但要看cache,還有看store buffer是否有內容,如果store buffer有該數據,那么就采用store buffer中的值。有了store forwarding的設計,上面的步驟[7]中就可以在store buffer獲取正確的a值是”1“而不是”0“,因此計算得到的b的結果就是2,和我們預期的一致了。


store forwarding解決了CPU 0的cache line和store buffer間的數據一致性問題,但是,在CPU 1的角度來看,是否也能看到一致的數據呢?我們來看下一個例子:
```
1 void foo(void)?
2 {?
3?????a = 1;?
4?????b = 1;?
5 }?
6?
7 void bar(void)?
8 {?
9????while (b == 0) continue;?
10??assert(a == 1);?
11 }
同樣的,a和b都是初始化成0.
```
我們假設CPU 0執行foo函數,CPU 1執行bar函數,a變量在CPU 1的cache中,b在CPU 0 cache中,執行的操作序列如下:
```
[1] CPU 0執行a=1的賦值操作,由于a不在local cache中,因此,CPU 0將a值放到store buffer中之后,發送了read invalidate命令到總線上去。

[2] CPU 1執行 while (b == 0) 循環,由于b不在CPU 1的cache中,因此,CPU發送一個read message到總線上,看看是否可以從其他cpu的local cache中或者memory中獲取數據。
[3] CPU 0繼續執行b=1的賦值語句,由于b就在自己的local cache中(cacheline處于modified狀態或者exclusive狀態),因此CPU0可以直接操作將新的值1寫入cache line。
[4] CPU 0收到了read message,將最新的b值”1“回送給CPU 1,同時將b cacheline的狀態設定為shared
[5] CPU 1收到了來自CPU 0的read response消息,將b變量的最新值”1“值寫入自己的cacheline,狀態修改為shared。
[6] 由于b值等于1了,因此CPU 1跳出while (b == 0)的循環,繼續前行。
[7] CPU 1執行assert(a == 1),這時候CPU 1的local cache中還是舊的a值,因此assert(a == 1)失敗。
[8] CPU 1收到了來自CPU 0的read invalidate消息,以a變量的值進行回應,同時清空自己的cacheline,但是這已經太晚了。
[9] CPU 0收到了read response和invalidate ack的消息之后,將store buffer中的a的最新值”1“數據寫入cacheline,然并卵,CPU 1已經assertion fail了。
```
CPU 1出現異常的assertion fail的根本原因是,CPU 0在發出read invalidate message后,并沒有等待CPU 1收到,就繼續執行將b改寫為1,也就是store buffer的存在導致了CPU 1先看到了b修改為1,后看到a被修改為1。遇到這樣的問題,CPU設計者也不能直接幫什么忙(除非去掉store buffer),畢竟CPU并不知道哪些變量有相關性,這些變量是如何相關的。不過CPU設計者可以間接提供一些工具讓軟件工程師來控制這些相關性。這些工具就是memory-barrier指令。要想程序正常運行,必須增加一些memory barrier的操作,具體如下:
```
1 void foo(void)?
2 {?
3?????a = 1;?
4?????smp_mb();?
5?????b = 1;?
6 }?
7?
8 void bar(void)?
9 {?
10?????while (b == 0) continue;?
11?????assert(a == 1);?
12}
```
smp_mb() 這個內存屏障的操作會在執行后續的store操作之前,首先flush store buffer(也就是將之前的值寫入到cacheline中)。達到這個目標有兩種方法:
```
[1] CPU遇到smp_mb內存屏障后,需要等待store buffer中的數據完成transaction并將strore buffer中的數據寫入cache line;
[2] CPU在遇到smp_mb內存屏障后,可以繼續前行,但是需要記錄一下store buffer中的數據順序,在store buffer中的數據嚴格按順序全部寫回cache line之前,其他數據不能先更新cache line,需要按照順序先寫到store buffer才能繼續前行。
```
通常采用的是方法[2],增加了smp_mb()后,執行序列如下:
```
[1] CPU 0執行a=1的賦值操作,由于a不在local cache中,因此,CPU 0將a值放到store buffer中之后,發送了read invalidate命令到總線上去。
[2] CPU 1執行 while (b == 0) 循環,由于b不在CPU 1的cache中,因此,CPU發送一個read message到總線上,看看是否可以從其他cpu的local cache中或者memory中獲取數據。
[3] CPU 0執行smp_mb()函數,給目前store buffer中的所有項做一個標記(后面我們稱之marked entries)。當然,針對我們這個例子,store buffer中只有一個marked entry就是“a=1”。
[4] CPU 0繼續執行b=1的賦值語句,雖然b就在自己的local cache中(cacheline處于modified狀態或者exclusive狀態),不過在store buffer中有marked entry,因此CPU 0不能直接操作將新的值1寫入cache line,取而代之是b的新值'1'被寫入store buffer(CPU 0也可以不執行b=1語句,等到a的transaction完成并寫回cache line,在執行b=1,將b的新值'1'寫入cache line),當然是unmarked狀態。
[5] CPU 0收到了read message,將b值”0“(新值”1“還在store buffer中)回送給CPU 1,同時將b cacheline的狀態設定為shared。
[6] CPU 1收到了來自CPU 0的read response消息,將b變量的值('0')寫入自己的cacheline,狀態修改為shared。
[7] 由于smp_mb內存屏障的存在,b的新值'1'隱藏在CPU 0的store buffer中,CPU 1只能看到b的舊值'0',這時CPU 1處于死循環中。
[8] CPU 1收到了來自CPU 0的read invalidate消息,以a變量的值進行回應,同時清空自己的cacheline。
[9] CPU 0收到CPU 1的響應msg,完成了a的賦值transaction,CPU 0將store buffer中的a值寫入cacheline,并且將cacheline狀態修改為modified狀態。
[10] 由于store buffer只有一項marked entry(對應a=1),因此,完成step 9之后,store buffer的b也可以進入cacheline了。不過需要注意的是,當前b對應的cache line的狀態是shared。
[11] CPU 0想將store buffer中的b的新值'1'寫回cache line。由于b的cache line是share的。CPU 0需要發送invalidate消息,請求b數據的獨占權。
[12] CPU 1收到invalidate消息,清空自己b的 cache line,并回送acknowledgement給CPU 0。
[13] CPU 1的某次循環執行到while (b == 0),這時發現b的cache line是Invalid的了,于是CPU 1發送read消息,請求獲取b的數據。
[14] CPU 0收到acknowledgement消息,將b對應的cache line修改成exclusive狀態,這時候,CPU 0終于可以將b的新值1寫入cache line了。
[15] CPU 0收到read消息,將b的新值1回送給CPU 1,同時將其local cache中b對應的cacheline狀態修改為shared。
[16]??CPU 1獲取來自CPU 0的b的新值,將其放入cache line中。
[17] 由于b值等于1了,因此CPU 1跳出while (b == 0)的循環,繼續前行。
[18] CPU 1執行assert(a == 1),不過這時候a值沒有在自己的cache line中,因此需要通過cache一致性協議從CPU 0那里獲得,這時候獲取的是a的最新值,也就是1值,因此assert成功。
```
從上面的執行序列可以看出,在調用memory barrier指令之后,使得CPU 0遲遲不能將b的新值'1'寫回cache line,從而使得CPU 1一直不能觀察到b的新值'1',造成CPU 1一直不能繼續前行。直觀上CPU 0似乎不受什么影響,因為CPU 0可以繼續前行,只是將b的新值'1'寫到store buffer而不能寫回cache line。不幸的是:每個cpu的store buffer不能實現的太大,其entry的數目不會太多。當cpu 0以中等的頻率執行store操作的時候(假設所有的store操作導致了cache miss),store buffer會很快的被填滿。在這種狀況下,CPU 0只能又進入等待狀態,直到cache line完成invalidation和ack的交互之后,可以將store buffer的entry寫入cacheline,從而為新的store讓出空間之后,CPU 0才可以繼續執行。這種狀況恰恰在調用了memory barrier指令之后,更容易發生,因為一旦store buffer中的某個entry被標記了,那么隨后的store都必須等待invalidation完成,因此不管是否cache miss,這些store都必須進入store buffer,這樣就很容易塞滿store buffer。


6.2.4 Invalidate Queue
store buffer之所以很容易被填充滿,主要是其他CPU回應invalidate acknowledge比較慢,如果能夠加快這個過程,讓store buffer盡快進入cache line,那么也就不會那么容易填滿了。


invalidate acknowledge不能盡快回復的主要原因是invalidate cacheline的操作沒有那么快完成,特別是cache比較繁忙的時候,這時,CPU往往進行密集的loading和storing的操作,而來自其他CPU的,對本CPU local cacheline的操作需要和本CPU的密集的cache操作進行競爭,只要完成了invalidate操作之后,本CPU才會發生invalidate acknowledge。此外,如果短時間內收到大量的invalidate消息,CPU有可能跟不上處理,從而導致其他CPU不斷的等待。


要想達到快速回復acknowledgement,一個解決方法是,引入一個緩沖隊列,接收到invalidate請求,可以先將請求入隊緩沖隊列,就可以回復acknowledgement消息了,后面在異步完成invalidate操作。于是硬件工程師,引入一個invalidate??queue,有invalidate queue的系統結構如下圖所示:


異步延后處理,也需要有個度才行。一旦將一個invalidate(例如針對變量a的cacheline)消息放入CPU的Invalidate Queue,實際上該CPU就等于作出這樣的承諾:在處理完該invalidate消息之前,不會發送任何相關(即針對變量a的cacheline)的MESI協議消息。為什么是在發出某個變量a的MESI協議消息的時候,需求去檢查invalidate queue看是否有變量a的invalidate消息呢?而不是在對該變量的任何操作都需要檢查以下invalidate queue呢?其實這樣在保證MESI協議正確性的情況下,進一步保證性能的折中方案。


因為,在單純考慮性能的情況下,少去檢查invalidate queue,周期性(一定時間,cpu沒那么繁忙、invalidate queue容量達到一定)批量處理invalidate queue中的消息,這樣性能能夠達到最佳。但是,這樣在某些情況下,使得MESI協議失效。例如:在一個4核的機器上,變量a初始值是'0',它cache在CPU 0和CPU 1的cache line中,狀態都是Share。
```
[1] CPU 0需要修改變量a的值為'1',CPU 0發送invalidate消息給其他CPU(1~3).
[2] 其他CPU(1~3)將invalidate消息放入invalidate queue,然后都回復給CPU 0.
[3] CPU 0收到響應后,將a的新值'1'寫入cache line并修改狀態為Modified。
[4] CPU 2需要讀取a的時候遇到cache miss,于是CPU 2發送read消息給其他CPU,請求獲取a的數據。
[5] CPU 1收到read請求,由于a在自己的cache line并且是share狀態的,于是CPU 1將a的invalid值'0'響應給CPU 2。
[6] CPU 2通過一個read消息獲取到一個過期的非法的值,這樣MESI協議無法保證數據一致性了。
```
于是,為了保證MESI協議的正確性,CPU在需要發出某個變量的a的MESI協議消息的時候,需要檢查invalidate queue中是否有該變量a的invalidate消息,如果有需要先出來完成這個invliadte消息后,才能發出正確的MESI協議消息。在合適的時候,發出正確的MESI協議是保證了不向其他CPU傳遞錯誤的信息,從而保證數據的一致性。但是,對于本CPU是否也可以高枕無憂呢?我們來看同上面一樣的一個例子:
```
1 void foo(void)?
2 {?
3?????a = 1;?
4?????smp_mb();?
5?????b = 1;?
6 }?
7?
8 void bar(void)?
9 {?
10?????while (b == 0) continue;?
11?????assert(a == 1);?
12 }
```
在上面的代碼片段中,我們假設a和b初值是0,并且a在CPU 0和CPU 1都有緩存的副本,即a變量對應的CPU0和CPU 1的cacheline都是shared狀態。b處于exclusive或者modified狀態,被CPU 0獨占。我們假設CPU 0執行foo函數,CPU 1執行bar函數,執行序列如下:
```
[1] CPU 0執行a=1的賦值操作,由于a在CPU 0 local cache中的cacheline處于shared狀態,因此,CPU 0將a的新值“1”放入store buffer,并且發送了invalidate消息去清空CPU 1對應的cacheline。
[2] CPU 1執行while (b == 0)的循環操作,但是b沒有在local cache,因此發送read消息試圖獲取該值。
[3] CPU 1收到了CPU 0的invalidate消息,放入Invalidate Queue,并立刻回送Ack。
[4] CPU 0收到了CPU 1的invalidate ACK之后,即可以越過程序設定內存屏障(第四行代碼的smp_mb() ),這樣a的新值從store buffer進入cacheline,狀態變成Modified。
[5]??CPU 0 越過memory barrier后繼續執行b=1的賦值操作,由于b值在CPU 0的local cache中,因此store操作完成并進入cache line。
[6] CPU 0收到了read消息后將b的最新值“1”回送給CPU 1,并修正該cache line為shared狀態。
[7] CPU 1收到read response,將b的最新值“1”加載到local cacheline。
[8] 對于CPU 1而言,b已經等于1了,因此跳出while (b == 0)的循環,繼續執行后續代碼
[9] CPU 1執行assert(a == 1),但是由于這時候CPU 1 cache的a值仍然是舊值0,因此assertion 失敗
[10] 該來總會來,Invalidate Queue中針對a cacheline的invalidate消息最終會被CPU 1執行,將a設定為無效,但,大錯已經釀成。
```
CPU 1出現assert失敗,是因為沒有及時處理invalidate queue中的a的invalidate消息,導致使用了本cache line中的一個已經是invalid的一個舊的值,這是典型的cache帶來的一致性問題。這個時候,我們也需要一個memory barrier指令來告訴CPU,這個時候應該需要處理invalidate queue中的消息了,否則可能會讀到一個invalid的舊值。
```
當CPU執行memory barrier指令的時候,對當前Invalidate Queue中的所有的entry進行標注,這些被標注的項被稱為marked entries,而隨后CPU執行的任何的load操作都需要等到Invalidate Queue中所有marked entries完成對cacheline的操作之后才能進行
```
因此,要想保證程序邏輯正確,我們需要給bar函數增加內存屏障的操作,具體如下:
```
1 void foo(void)?
2 {?
3?????a = 1;?
4?????smp_mb();?
5?????b = 1;?
6 }?
7?
8 void bar(void)?
9 {?
10????while (b == 0) continue;?
11?????smp_mb();?
12?????assert(a == 1);?
13 }
```
bar()函數添加smp_mb內存屏障后,執行序列如下:
```
[1] ~ [8] 同上
[9] CPU 1遇到smp_mb內存屏障,發現下一條語句是load a,這個時候CPU 1不能繼續執行代碼,只能等待,直到Invalidate Queue中的message被處理完成
[10] CPU 1處理Invalidate Queue中緩存的Invalidate消息,將a對應的cacheline設置為無效。
[11] 由于a變量在local cache中無效,因此CPU 1在執行assert(a == 1)的時候需要發送一個read消息去獲取a值。
[12] CPU 0用a的新值1回應來自CPU 1的請求。
[13] CPU 1獲得了a的新值,并放入cacheline,這時候assert(a == 1)不會失敗了。
```
在我們上面的例子中,memory barrier指令對store buffer和invalidate queue都進行了標注,不過,在實際的代碼片段中,foo函數不需要mark invalidate queue,bar函數不需要mark store buffer。因此,許多CPU architecture提供了弱一點的memory barrier指令只mark其中之一。如果只mark invalidate queue,那么這種memory barrier被稱為read memory barrier。相應的,write memory barrier只mark store buffer。一個全功能的memory barrier會同時mark store buffer和invalidate queue。


我們一起來看看讀寫內存屏障的執行效果:對于read memory barrier指令,它只是約束執行CPU上的load操作的順序,具體的效果就是CPU一定是完成read memory barrier之前的load操作之后,才開始執行read memory barrier之后的load操作。read memory barrier指令象一道柵欄,嚴格區分了之前和之后的load操作。同樣的,write memory barrier指令,它只是約束執行CPU上的store操作的順序,具體的效果就是CPU一定是完成write memory barrier之前的store操作之后,才開始執行write memory barrier之后的store操作。全功能的memory barrier會同時約束load和store操作,當然只是對執行memory barrier的CPU有效。


現在,我們可以改一個用讀寫內存屏障的版本了,具體如下:
```
1 void foo(void)?
2 {?
3?????a = 1;?
4?????smp_wmb();?
5?????b = 1;?
6 }?
7?
8 void bar(void)?
9 {?
10????while (b == 0) continue;?
11?????smp_rmb();?
12?????assert(a == 1);?
13 }
```
可見,memory barrier需要成對使用才能保證程序的正確性。什么情況下使用memory barrier,使用怎樣的memory barrier,和CPU架構有那些相關性呢?


6.3 How Memory Barriers?

memory barrier的語義在不同CPU上是不同的,因此,想要實現一個可移植的memory barrier的代碼需要對形形色色的CPU上的memory barrier進行總結。幸運的是,無論哪一種cpu都遵守下面的規則:
```
[1]、從CPU自己的視角看,它自己的memory order是服從program order的
[2]、從包含所有cpu的sharebility domain的角度看,所有cpu對一個共享變量的訪問應該服從若干個全局存儲順序
[3]、memory barrier需要成對使用
[4]、memory barrier的操作是構建互斥鎖原語的基石
```
6.3.1 有條件的順序保證
要保證程序在多核CPU中執行服從program order,那么我們需要成對使用的memory barrier,然而成對的memory barrier并不能提供絕對的順序保證,只能提供有條件的順序保證。那么什么是有條件的順序保證?考慮下面一個訪問例子(這里的access可以是讀或寫):

從CPU1角度來看,對A的訪問總是先于對B的訪問。但是,關鍵的是從CPU2的角度來看,CPU1對A、B的訪問順序是否就一定是A優先于B呢?假如在CPU2感知CPU1對A的訪問結果的情況下,是否可以保證CPU2也能感知CPU1對B的訪問結果呢?這是不一定的,例如執行時序如下,那么顯然,在CPU2感知CPU1對A的訪問結果的情況下,是并不能感知CPU1對B的訪問結果(CPU2對A的訪問要早于CPU1對B的訪問)。


另外,如果CPU1對B的訪問結果已經被CPU2感知到了,那么,在這個條件下,CPU1對A的訪問結果就一定能夠被CPU2感知到。這就是觀察者(CPU2)在滿足一定條件下才能保證這個memory的訪問順序。

對于上面例子中的access操作,在內存上包括load和store兩種不同操作,下面列出了CPU1和CPU2不同的操作組合共16個,下面來詳細描述一下,在不同的操作組合下memory barrier可以做出怎樣的保證。


由于CPU架構千差萬別,上面的16種組合可以分成3類
```
[1] Portable Combinations -- 通殺所有CPU
[2] Semi-Portable Combinations -- 現代CPU可以work,但是不適應在比較舊的那些CPU
[3] Dubious Combinations -- 基本是不可移植的
```

6.3.1.1 通殺所有CPU
(1) Pairing 1
情況3,CPU執行代碼如下:(A和B的初值都是0)

| CPU1 | CPU2 |
| ------ | ------ |
| X = A; | B = 1; |?
| smp_mb(); | smp_mb(); |
| Y = B; | A = 1; |

對于這種情況,兩個CPU都執行完上面的代碼后,如果X的值是1,那么我們可以斷定Y也是等于1的。也就是如果CPU1感知到了CPU2對A的訪問結果,那么可以斷定CPU1也必能感知CPU2對B的訪問結果。但是,如果X的值是0,那么memory barrier的條件不存在,于是Y的值可能是0也可能是1。
對于情況C,它是和情況1是對稱,于是結論也是類似的:(A和B的初值都是0)

同樣,兩個CPU都執行完上面的代碼后,如果Y的值是1,那么可以斷定X的值也是1。
(2) Pairing 2
情況5,CPU執行代碼如下:(A和B的初值都是0)

兩個CPU都執行完上面的代碼后,在不影響邏輯的情況下,在CPU2的A=1;前面插入代碼Z=X,根據情況C,如果Y的值是1,那么Z的值就一定是A,由于Z=X執行在A=1前面,那么Z的值是A的初始值0,于是X的值一定是0。同樣,如果X等于1,那么我們一定可以得到Y等于0;
(3) Pairing 3
情況7,CPU執行代碼如下:(A和B的初值都是0)

兩個CPU都執行完上面的代碼后,在不影響邏輯的情況下,在CPU1的B=1;前面插入代碼Z=B,根據情況3,如果X等于1,那么可以斷定Z等于2,也就是在CPU1執行完畢Z=B代碼前,B的值是2,由于CPU1在執行完Z=B后會執行B=1,于是對CPU1而已,最后B的值是1。
通過上面(1) ,如果CPU1執行的全是store操作,而CPU2執行的全是load操作(對稱下,CPU2執行的全是store操作,而CPU1執行的全是load操作),那么會有一個memory barrier條件使得執行得到一個確定的順序,并且是通吃所有CPU的。而,(2)和(3)經過插入代碼也可以轉換成(1)的情況。
情況D,CPU執行代碼如下:(A和B的初值都是0)

該情況是情況7是類似的。在Y等1的時候,最終A等于2.

6.3.1.2 現代CPU可以work,但是不適應在比較舊的那些CPU
(1) Ears to Mouths
情況A,CPU執行代碼如下:(A和B初值都是0,其他變量初始值是-1)

這種情況下,比較容易推算出X等1的時候,Y可能為0也可能為1,當X等于0的時候,也比較容易推算出Y值可以為1。但是,X等0的時候,Y有沒可能也是0呢?


我們通過插入代碼(Z=X),這樣就轉換成情況C,在X等于0,Z等于0的時候,那么memory barrier條件成立,于是Y必然等1。然而,如果X等于0的時候,Z不等于0,這個時候memory barrier條件就不能成立了,這個時候Y就可能為0。


下面我們來講下,上面情況下會出現X和Y同時為0。在一個有Invalidate queue和store buffer的系統中,B和X在CPU1的local cache中并且是獨占的,A和Y在CPU2的local cache中并且也是獨占的。CPUs的執行序列如下:
```
[1] CPU1對A發起store操作,由于A不在CPU1的cache中,CPU1發起invalidate message,當然,CPU1不會停下它的腳步,將A的新值'1'放入store buffer,它就繼續往下執行
[2] smp_mb使得CPU1對store buffer中的entry進行標注(當然也對Invalidate Queue進行標注,不過和本場景無關),store A的操作變成marked狀態?
[3] CPU2對B發起store操作,由于B不在CPU2的cache中,CPU2發起invalidate message,當然,CPU2不會停下它的腳步,將B的新值'1'放入store buffer,它就繼續往下執行
[4] CPU2收到CPU1的invalidate message將該message放入Invalidate Queue后繼續前行。
[5] smp_mb使得CPU2對store buffer中的entry進行標注(當然也對Invalidate Queue進行標注),store B的操作變成marked狀態
[6] CPU1收到CPU2的invalidate message將該message放入Invalidate Queue后繼續前行。
[7] CPU1前行執行load B,由于B在CPU1的local cache獨占的(CPU1并不需要發送任何MESI協議消息,它并不需要立即處理Invalidate Queue里面的消息),于是CPU1從local cache中得到B的值'0',接著CPU1繼續執行store X,由于X也在CPU1的local cache獨占的,于是,CPU1將X的新值修改為B的值'0'并將其放入store buffer中。
[8] CPU2前行執行load A,由于A在CPU2的local cache獨占的(CPU2并不需要發送任何MESI協議消息,它并不需要立即處理Invalidate Queue里面的消息),于是CPU2從local cache中得到A的值'0',接著CPU2繼續執行store Y,由于Y也在CPU2的local cache獨占的,于是,CPU2將Y的新值修改為B的值'0'并將其放入store buffer中。
[9] CPU1開始處理Invalidate Queue里面的消息,將本local cache中的B置為Invalide,同時響應Invalidate response message給CPU2
[10] CPU2收到Invalidate response message后,這個時候可以將store buffer里面的B和Y寫回cache line,最后B為1,Y為0。
[11] CPU1和CPU2類似,最終A為1,X為0.
```
(2) Pass in the Night
情況F,CPU執行代碼如下:(A和B初值都是0,其他變量初始值是-1)

| CPU1 | CPU2 |
| ------ | ------ |
| A = 1; | B = 2;|?
| smp_mb(); | smp_mb(); |
| B = 1; | A = 2; |

情況F,正常情況下,無論如何,但是無論如何,在兩個CPU都執行完上面的代碼之后{A==1,B==2} 這種情況不可能發生。不幸的是,在一些老的CPU架構上,是可能出現{A==1,B==2} 的,出現這種情況和上面的原因有點類似,下面也簡單描述一下,在一個有Invalidate queue和store buffer的系統中,B在CPU1的local cache中并且是獨占的,A在CPU2的local cache中并且也是獨占的。CPUs的執行序列如下:
```
[1]~[6]和 (1) Ears to Mouths中的基本一樣
[7] CPU1繼續前行,由于B在CPU1的local cache獨占的(CPU1并不需要發送任何MESI協議消息,它并不需要立即處理Invalidate Queue里面的消息),于是,CPU1將B的新值'1'放入store buffer中。
[8] CPU2繼續前行,由于A在CPU2的local cache獨占的(CPU1并不需要發送任何MESI協議消息,它并不需要立即處理Invalidate Queue里面的消息),于是,CPU2將A的新值'2'放入store buffer中。
[9] CPU1開始處理Invalidate Queue里面的消息,將本local cache中的B置為Invalide(這個時候store buffer里面B的新值'1'也被invalidate了),同時響應Invalidate response message給CPU2
[9] CPU2開始處理Invalidate Queue里面的消息,將本local cache中的置為Invalide(這個時候store buffer里面A的新值'2'也被invalidate了),同時響應Invalidate response message給CPU1
[10] CPU1收到Invalidate response message,這個時候可以將store buffer中的A=1刷到cache line,最終A的值為1
[11] CPU2收到Invalidate response message,這個時候可以將store buffer中的B=2刷到cache line,最終B的值為2
```
到這來,大家應該會發現,第一個賦值(對于CPU1而言是A = 1,對于CPU2而言是B = 2)其實是pass in the night,靜悄悄的走過,而第二個賦值(對于CPU1而言是B = 1,對于CPU2而言是A = 2)則會后發先至,最終導致第一個賦值先發而后至覆蓋第二個賦值。
其實,只要符合下面的使用模式,上面描述的操作順序(第二個store的結果被第一個store覆蓋)都是有可能發生的:

| CPU1 | CPU2 |
| ------ | ------ |
| A = 1; | B = 2;|?
| smp_mb(); | smp_mb(); |
|xxxx; | xxxx; |
前面說的'ears to mouths'也是這種模式,不過,對于21世紀的硬件系統而言,硬件工程師已經幫忙解決了上面的問題,因此,軟件工程師可以安全的使用Stores “Pass in the Night”。

6.3.1.3 基本不可移植
剩下的情況0、1、2、4、6、8、9這7種情況的組合,即使是在21世紀的那些新的CPU硬件平臺上,也是不能夠保證是可移植的。當然,在一些硬件平臺上,我們還是可以得到一些確定的執行順序的。
(1) Ears to Ears
情況0,CPUs上全是load操作

| CPU1 | CPU2 |
| ------ | ------ |
| load A; | load B;|?
| smp_mb(); | smp_mb(); |
| load B; | load A; |
由于load操作不能改變memory的狀態,因此,一個CPU上的load是無法感知到另外一側CPU的load操作的。不過,如果CPU2上的load B操作返回的值比CPU 1上的load B返回的值新的話(即CPU2上load B晚于CPU1的load B執行),那么可以推斷CPU2的load A返回的值要么和CPU1上的load A返回值一樣新,要么加載更新的值。
(2) Mouth to Mouth, Ear to Ear
這個組合的特點是一個變量只是執行store操作,而另外一個變量只是進行load操作。執行序列如下:

| CPU1 | CPU2 |
| ------ | ------ |
| load A; | store B;|?
| smp_mb(); | smp_mb(); |
| store B; | load A; |
這種情況下,如果CPU2上的store B最后發生(也就是,上面代碼執行完畢后,在執行一次load B得到的值是CPU2 store B的值),那么可以推斷CPU2的load A返回的值要么和CPU1上的load A返回值一樣新,要么加載更新的值。
(3) Only One Store

| CPU1 | CPU2 |
| ------ | ------ |
| load A; | load B;|?
| smp_mb(); | smp_mb(); |
| load B; | store A; |
這種情況下,只有一個變量的store操作可以被另外的CPU上的load操作觀察到,如果在CPU1上運行的load A感知到了在CPU2上對A的賦值,那么,CPU1上的load B必然能觀察到和CPU2上load B一樣的值或者更新的值。

6.3.2 memory barrier內存屏障類型

6.3.2.1 顯式內存屏障
6.3.1章節列舉的16種情況的例子中內存屏障smp_mb()指的是一種全功能內存屏障(General memory barrier),然而全功能的內存屏障對性能的殺傷較大,某些情況下我們可以使用一些弱一點的內存屏障。在有Invalidate queue和store buffer的系統中,全功能的內存屏障既會mark store buffer也會mark invalidate queue,對于情況3,CPU1全是load它只需要mark invalidate queue即可,相反CPU2全是store,它只需mark store buffer即可,于是CPU1只需要使用讀內存屏障(Read memory barrier),CPU2只需使用寫內存屏障(Write memory barrier)。
情況3,修改如下

| CPU1 | CPU2 |
| ------ | ------ |
| X = A; | B = 1; |?
| read_mb(); | write_mb(); |
| Y = B; | A = 1; |
到這來,我們知道有3種不同的內存屏障,還沒有其他的呢?我們來看一個例子:
初始化
int A = 1;
int B = 2;
int C = 3;
int *P = &A;
int *Q = &B;


通常情況下,Q最后要么等于&A,要么等于&B。也就是說:Q == &A, D == 1 或者 Q == &B, D == 4,絕對不會出現Q == &B, D == 2的情形。然而,讓人吃驚的是,DEC Alpha下,就可能出現Q == &B, D == 2的情形。


于是,在DEC Alpha下,CPU2上的Q=P下面需要插入一個memory barrier來保證程序順序,這來用一個讀內存屏障(read_mb)即可,但是我們發現CPU2上的Q = P和D = \*Q是一個數據依賴關系,是否可以引入一個更為輕量的內存屏障來解決呢?


于是這里引入一種內存屏障-數據依賴內存屏障dd_mb(data dependency memory barrier),dd_mb是一種比read_mb要弱一些的內存屏障(這里的弱是指對性能的殺傷力要弱一些)。read_mb適用所有的load操作,而ddmb要求load之間有依賴關系,即第二個load操作依賴第一個load操作的執行結果(例如:先load地址,然后load該地址的內容)。ddmb被用來保證這樣的操作順序:在執行第一個load A操作的時候(A是一個地址變量),務必保證A指向的數據已經更新。只有保證了這樣的操作順序,在第二load操作的時候才能獲取A地址上保存的新值。

在純粹的數據依賴關系下使用數據依賴內存屏障dd_mb來保證順序,但是如果加入了控制依賴,那么僅僅使用dd_mb是不夠的,需要使用read_mb,看下面例子:

由于加入了條件if (t)依賴,這就不是真正的數據依賴了,在這種情況下,CPU會進行分支預測,可能會"抄近路"先去執行*Q的load操作,在這種情況下,需要將data_dependency_mb改成read_mb。
到這來,我們知道有4中不同的內存屏障種類:
```
[1] Write (or store) memory barriers -- 寫內存屏障
[2] Data dependency barriers -- 數據依賴內存屏障
[3] Read (or load) memory barriers -- 讀內存屏障
[4] General memory barriers -- 全功能內存屏障
```
6.3.2.2 隱式內存屏障
有些操作可以隱含memory barrier的功能,主要有兩種類型的操作:一是加鎖操作,另外一個是釋放鎖的操作。
```
[1] LOCK operations -- 加鎖操作
[2] UNLOCK operations -- 釋放鎖操作
```
(1) 加鎖操作被認為是一種half memory barrier,加鎖操作之前的內存訪問可以任意滲透過加鎖操作,在其他執行,但是,另外一個方向絕對是不允許的:即加鎖操作之后的內存訪問操作,必須在加鎖操作之后完成。
(2) 和lock操作一樣,unlock也是half memory barrier。它確保在unlock操作之前的內存操作先于unlock操作完成,也就是說unlock之前的操作絕對不能越過unlock這個籬笆,在其后執行。當然,另外一個方向是OK的,也就是說,unlock之后的內存操作可以在unlock操作之前完成。
我們看下面一個例子:
```
1 *A = a;?
2 LOCK?
3 C = 1;
4 UNLOCK?
5 *B = b;
```
上面的程序有可能按照下面的順序執行:
```
2 LOCK?
3 C = 1;
5 *B = b;?
1 *A = a;?
4 UNLOCK
```
通過上面,我們得知,經LOCK-UNLOCK對不能實現完全的內存屏障的功能,但是,它們也的確會影響內存訪問順序,參考下面的例子:
多個CPU對一把鎖操作的場景:

這種情況下,CPU1或者CPU2,只能有一個進入臨界區,如果是CPU1進入臨界區的話,對A B C的賦值操作,必然在對F G H變量賦值之前完成。如果CPU2進入臨界區的話,對E F G的賦值操作,必然在對B C D變量賦值之前完成。

6.3.3 C++11 memory order
要編寫出正確的lock free多線程程序,我們需要在正確的位置上插入合適的memory barrier代碼,然而不同CPU架構對于的memory barrier指令千差萬別,要寫出可移植的C++程序,我們需要一個語言層面的Memory Order規范,以便編譯器可以根據不同CPU架構插入不同的memory barrier指令,或者并不需要插入額外的memory barrier指令。


有了這個Memory Order規范,我們可以在high level language層面實現對在多處理器中多線程共享內存交互的次序控制,而不用考慮compiler,CPU arch的不同對多線程編程的影響了。

C++11提供6種可以應用于原子變量的內存順序:
```
[1] memory_order_relaxed
[2] memory_order_consume
[3] memory_order_acquire
[4] memory_order_release
[5] memory_order_acq_rel
[6] memory_order_seq_cst
```
上面6種內存順序描述了三種內存模型(memory model):
```
[1] sequential consistent(memory_order_seq_cst)
[2] relaxed(momory_order_relaxed)
[3] acquire release(memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel)
```
6.3.3.1 C++11中的各種關系
C++11引入上面6種內存順序本質上是為了解決"visible side-effects"的問題,也就是讀操作的返回值問題,通俗來講:
```
線程1執行寫操作A之后,如何可靠并高效地保證線程2執行的讀操作B,load A的結果是完整可見的?
```
為了解決"visible side-effects"這個問題,C++11引入"happens-before"關系,其定義如下:
```
Let A and B represent operations performed by a multithreaded process. If A happens-before B, then the memory effects of A effectively become visible to the thread performing B before B is performed.
```
OK,現在問題就轉化為:如何在A、B兩個操作之間建立起happens-before關系。在推導happens-before關系前,我們先描述下面幾個關系:


6.3.3.1.1 Sequenced-before 關系
定義如下:
```
Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations.
```
Sequenced-before是在同一個線程內,對求值順序關系的描述,它是非對稱的,可傳遞的關系。
```
[1] 如果A is sequenced-before B,代表A的求值會先完成,才進行對B的求值
[2] 如果A is not sequenced before B 而且 B is sequenced before A,代表B的求值會先完成,才開始對A的求值。
[3] 如果A is not sequenced before B 而且 B is not sequenced before A,這樣求值順序是不確定的,可能A先于B,也可能B先于A,也可能兩種求值重疊。
```
6.3.3.1.2 Carries??a dependency 關系
定義如下:
```
Within the same thread, evaluation A that is sequenced-before evaluation B may also carry a dependency into B (that is, B depends on A), if any of the following is true
1) The value of A is used as an operand of B, except
????a) if B is a call to std::kill_dependency
????b) if A is the left operand of the built-in &&, ||, ?:, or , operators.
2) A writes to a scalar object M, B reads from M
3) A carries dependency into another evaluation X, and X carries dependency into B
```
簡單來講,carries-a-dependency-to 嚴格應用于單個線程,建立了 操作間的數據依賴模型:如果操作 A 的結果被操作 B 作為操作數,那么 A carries-a-dependency-to B(一個直觀的例子:B=M[A] ), carries a dependency具有傳遞性。
######6.3.3.1.3 Dependency-ordered before 關系
該關系描述的是線程間的兩個操作間的關系,定義如下:
```
Between threads, evaluation A is dependency-ordered before evaluation B if any of the following is true
1) A performs a release operation on some atomic M, and, in a different thread, B performs a consume operation on the same atomic M, and B reads a value written by any part of the release sequence headed by A.
2) A is dependency-ordered before X and X carries a dependency into B.
```
case 1指的是:線程1的操作A對變量M執行“release”寫,線程2的操作B對變量M執行“consume”讀,并且操作B讀取到的值源于操作A之后的“release”寫序列中的任何一個(包括操作A本身)。
case 2描述的是一種傳遞性。


6.3.3.1.4 Synchronized-with 關系
定義如下:
```
An atomic operation A that performs a release operation on an atomic object M synchronizes withan atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.
```
該關系描述的是,對于在變量 x 上的寫操作 W(x) synchronized-with 在該變量上的讀操作 R(x), 這個讀操作欲讀取的值是 W(x) 或同一線程隨后的在 x 上的寫操作 W’,或任意線程一系列的在 x 上的 read-modify-write 操作(如 fetch_add()或
compare_exchange_weak())而這一系列操作最初讀到 x 的值是 W(x) 寫入的值。
例如:A Write-Release Can Synchronize-With a Read-Acquire,簡單來說, 線程1的A操作寫了變量x,線程2的B操作讀了變量x,B讀到的是A寫入的值或者更新的值,那么A, B 間存在 synchronized-with 關系。


6.3.3.1.5 Inter-thread happens-before 關系
定義如下:
```
Between threads, evaluation A inter-thread happens before evaluation B if any of the following is true
1) A synchronizes-with B
2) A is dependency-ordered before B
3) A synchronizes-with some evaluation X, and X is sequenced-before B
4) A is sequenced-before some evaluation X, and X inter-thread happens-before B
5) A inter-thread happens-before some evaluation X, and X inter-thread happens-before B
```
Inter-thread happens-before 關系具有傳遞性。該關系描述的是,如果A inter-thread happens-before B,則線程1的A操作對memory的訪問結果,會在線程2的B操作執行前對線程2是可見的。
######6.3.3.1.6 Happens-before 關系
定義如下:
```
Regardless of threads, evaluation A happens-before evaluation B if any of the following is true:
1) A is sequenced-before B
2) A inter-thread happens before B
```
Happens-before 指明了哪些指令將看到哪些指令的結果。
對于單線程,sequenced-before關系即是Happens-before 關系,表明了操作 A 排列在另一個操作 B 之前。
對于多線程,則inter-thread happens before關系即是Happens-before 關系。
Happens-before 關系推導圖總結如下:

????

6.3.3.2 6種memory order描述
下面我們分別來解析一下上面說的6種memory order的作用以及用法。


6.3.3.2.1 順序一致次序 - memory_order_seq_cst
SC是C++11中原子變量的默認內存序,它意味著將程序看做是一個簡單的序列。如果對于一個原子變量的操作都是順序一致的,那么多線程程序的行為就像是這些操作都以一種特定順序被單線程程序執行。
從同步的角度來看,一個順序一致的 store 操作 synchroniezd-with 一個順序一致的需要讀取相同的變量的 load 操作。除此以外,順序模型還保證了在 load 之后執行的順序一致原子操作都得表現得在 store 之后完成。
順序一致次序對內存序要求比較嚴格,對性能的損傷比較大。

6.3.3.2.2 松弛次序 - memory_order_relaxed
在原子變量上采用 relaxed ordering 的操作不參與 synchronized-with 關系。在同一線程內對同一變量的操作仍保持happens-before關系,但這與別的線程無關。在 relaxed ordering 中唯一的要求是在同一線程中,對同一原子變量的訪問不可以被重排。
我們看下面的代碼片段,x和y初始值都是0
```
// Thread 1:
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// Thread 2:
r2 = x.load(std::memory_order_relaxed); // C?
y.store(42, std::memory_order_relaxed); // D
```
由于標記為memory_order_relaxed的atomic操作對于memory order幾乎不作保證,那么最終可能輸出r1 == r2 == 42,造成這種情況可能是編譯器對指令的重排,導致在線程2中D操作先于C操作完成。
Relaxed ordering比較適用于“計數器”一類的原子變量,不在意memory order的場景。


6.3.3.2.3 獲取-釋放次序 --memory_order_release, memory_order_acquire, memory_order_acq_rel
Acquire-release 中沒有全序關系,但它供了一些同步方法。在這種序列模型下,原子 load 操作是 acquire 操作(memory_order_acquire),原子 store 操作是release操作(memory_order_release), 原子read_modify_write操作(如fetch_add(),exchange())可以是 acquire, release 或兩者皆是(memory_order_acq_rel)。同步是成對出現的,它出現在一個進行 release 操作和一個進行 acquire 操作的線程間。一個 release 操作 syncrhonized-with 一個想要讀取剛才被寫的值的 acquire 操作。
也就是,如果在線程1中,操作A對原子M使用memory_order_release來進行atomic store,而在另外一個線程2中,操作B對同一個原子變量M使用memory_order_acquire來進行atomic load,那么線程1在操作A之前的所有寫操作(包括操作A),都會在線程2完成操作B后是可見的。
我們看下面一個例子:
```
std::atomic<std::string*> ptr;
int data;
?
void producer()
{
????std::string* p??= new std::string("Hello");//A
????data = 42;//B
????ptr.store(p, std::memory_order_release);//C
}
?
void consumer()
{
????std::string* p2;
????while (!(p2 = ptr.load(std::memory_order_acquire)))//D
????????;
????assert(*p2 == "Hello"); //E
????assert(data == 42); //F
}
?
int main()
{
????std::thread t1(producer);
????std::thread t2(consumer);
????t1.join(); t2.join();
}
```
首先,我們可以直觀地得出如下關系:A sequenced-before B sequenced-before C、C synchronizes-with D、D sequenced-before E sequenced-before F。利用前述happens-before推導圖,不難得出A happens-before E、B happens-before F,因此,這里的E、F兩處的assert永遠不會fail。

6.3.3.2.4 數據依賴次序??memory_order_consume
memory_order_consume是輕量級的memory_order_acquire,是 memory_order_acquire 內存序的特例:它將同步數據限定為具有直接依賴的數據。能夠用memory_order_consume的場景下就一定能夠使用memory_order_acquire,引入memory_order_consume的目的是為了在一些已知的PowerPC和ARM等weakly-ordered CPUs上,對于在對有數據依賴的數據進行同步的時候不要插入額外memory barrier,因為它們本身就能保證在有數據依賴的情況下機器指令的內存順序,少了額外的memory barrier對性能提升還是比較大的。


memory_order_consume描述的是dependency-ordered-before關系。我們看上面的例子,把D中memory_order_acquire改成memory_order_consume會怎樣呢?


這個時候,由于p2和ptr有數據依賴,上面例子基本的關系對是:A sequenced-before B sequenced-before C、C dependency-ordered before D、D carries a dependency into E, E sequenced-before F。


根據關系推導,由C dependency-ordered before D && D carries a dependency into E得到C dependency-ordered before E,進一步得到C Inter-thread happens-before E,繼而A sequenced-before C && C Inter-thread happens-before E得到A Inter-thread happens-before E,于是得到A Happens-before E,E永遠不會assert fail。對于F,由于D、F間不存在 carries a dependency關系,那么F的assert是可能fail的。


通常情況下,我們可以通過源碼的小調整實現從Release-Acquire ordering到Release-Consume ordering的轉換,下面是一個

例子:


7. 總結

本文通過一個無鎖隊列為引子,介紹了無鎖編程涉及的6個技術要點,其中內存屏障是最為關鍵,使用什么樣的memory barrier,什么時候使用memory barrier又是其中的重中之重。memory barrier不容易理解,要想正確高效地使用memory barrier就更難了,通常情況下,能不直接用memory barrier原語就不用,最好使用鎖(互斥量)等互斥原語這樣的隱含了memory barrier功能的原語。鎖在在很長一段時間都被誤解了,認為鎖是慢的,由于鎖的引入,給性能帶來巨大的瓶頸是很常見的。但這并不意味著所有的鎖都是緩慢的,當我們使用輕量級鎖并控制好鎖競爭的時候,鎖依然有非常出色的性能表現,鎖不慢,鎖競爭慢。


總結

以上是生活随笔為你收集整理的下篇 | 说说无锁(Lock-Free)编程那些事(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

a片在线免费观看 | 精品国产乱码久久久久乱码 | 性欧美疯狂xxxxbbbb | 麻豆精产国品 | 午夜精品一区二区三区在线观看 | 亚洲成a人片在线观看无码3d | 88国产精品欧美一区二区三区 | 成人性做爰aaa片免费看 | 亚洲成a人片在线观看日本 | 亚洲色偷偷男人的天堂 | 欧美激情综合亚洲一二区 | аⅴ资源天堂资源库在线 | 精品国产乱码久久久久乱码 | 亚洲精品一区二区三区婷婷月 | 亚洲精品中文字幕乱码 | 大肉大捧一进一出好爽视频 | 日本高清一区免费中文视频 | 中文字幕无线码 | 人妻插b视频一区二区三区 | 国产xxx69麻豆国语对白 | 亚洲一区二区三区含羞草 | 蜜桃无码一区二区三区 | 荫蒂被男人添的好舒服爽免费视频 | 欧美xxxx黑人又粗又长 | 国产电影无码午夜在线播放 | 久久久精品成人免费观看 | 精品久久久无码中文字幕 | 蜜桃av抽搐高潮一区二区 | 久久久久久久女国产乱让韩 | 国产无套内射久久久国产 | 久久99久久99精品中文字幕 | 亚洲の无码国产の无码步美 | 一本久久a久久精品vr综合 | 精品 日韩 国产 欧美 视频 | 性生交大片免费看女人按摩摩 | 欧美人与物videos另类 | 国产一区二区三区四区五区加勒比 | 久久久精品国产sm最大网站 | 亚洲欧美国产精品专区久久 | 久久亚洲中文字幕精品一区 | 蜜臀av无码人妻精品 | 欧美性色19p | 国产精品久久久久9999小说 | 日韩欧美成人免费观看 | 丰满妇女强制高潮18xxxx | 丰满少妇人妻久久久久久 | 亚洲中文字幕在线无码一区二区 | 无码人妻精品一区二区三区下载 | 国产亚洲精品久久久久久国模美 | 日产精品99久久久久久 | 国产成人无码一二三区视频 | 久久午夜夜伦鲁鲁片无码免费 | 99er热精品视频 | 中文字幕av无码一区二区三区电影 | 久久99国产综合精品 | 狂野欧美性猛xxxx乱大交 | 成人片黄网站色大片免费观看 | 国产亚洲视频中文字幕97精品 | 国产亚洲精品久久久闺蜜 | 日韩人妻系列无码专区 | 暴力强奷在线播放无码 | 亚洲无人区一区二区三区 | 久久无码中文字幕免费影院蜜桃 | 国内少妇偷人精品视频免费 | 国产成人无码av片在线观看不卡 | 狠狠综合久久久久综合网 | 久久久久成人片免费观看蜜芽 | 亚洲中文字幕在线无码一区二区 | 秋霞成人午夜鲁丝一区二区三区 | 三级4级全黄60分钟 | 丰满妇女强制高潮18xxxx | 俺去俺来也在线www色官网 | 免费人成在线视频无码 | 国产明星裸体无码xxxx视频 | 麻豆蜜桃av蜜臀av色欲av | 久久亚洲精品中文字幕无男同 | 丰满护士巨好爽好大乳 | 欧美性生交活xxxxxdddd | 色妞www精品免费视频 | 久久精品国产99久久6动漫 | 男女爱爱好爽视频免费看 | 久久99精品久久久久久动态图 | 国产亲子乱弄免费视频 | 国产精品怡红院永久免费 | 精品午夜福利在线观看 | 国产两女互慰高潮视频在线观看 | 偷窥日本少妇撒尿chinese | 2020久久超碰国产精品最新 | 国产精品久久久久久久9999 | 国产免费无码一区二区视频 | 国产精品无码永久免费888 | 国产亚洲精品久久久闺蜜 | 蜜桃臀无码内射一区二区三区 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产熟女一区二区三区四区五区 | 欧洲欧美人成视频在线 | 日本一区二区三区免费高清 | 女人高潮内射99精品 | 中文字幕精品av一区二区五区 | 国产莉萝无码av在线播放 | 思思久久99热只有频精品66 | 欧美日本免费一区二区三区 | 国产成人无码一二三区视频 | 国产黄在线观看免费观看不卡 | 色婷婷欧美在线播放内射 | 亚洲区欧美区综合区自拍区 | 久久精品99久久香蕉国产色戒 | 国产人妖乱国产精品人妖 | 久久久国产一区二区三区 | 色综合久久久久综合一本到桃花网 | 日韩少妇内射免费播放 | 乱人伦中文视频在线观看 | 亚洲精品一区二区三区婷婷月 | 东北女人啪啪对白 | 亚洲一区二区三区四区 | 亚洲 高清 成人 动漫 | 中文字幕人成乱码熟女app | 精品久久久中文字幕人妻 | 久久亚洲精品中文字幕无男同 | 丰满护士巨好爽好大乳 | 最新国产乱人伦偷精品免费网站 | 51国偷自产一区二区三区 | 青青青手机频在线观看 | 国产99久久精品一区二区 | 超碰97人人做人人爱少妇 | 久久人人爽人人爽人人片ⅴ | 97精品人妻一区二区三区香蕉 | 久久久久久亚洲精品a片成人 | 国产熟女一区二区三区四区五区 | 成在人线av无码免费 | 无遮挡国产高潮视频免费观看 | 国产xxx69麻豆国语对白 | 人妻人人添人妻人人爱 | 在线а√天堂中文官网 | 亚洲春色在线视频 | 国产亚洲人成在线播放 | 国产口爆吞精在线视频 | 丁香啪啪综合成人亚洲 | 日本精品高清一区二区 | 少妇久久久久久人妻无码 | 国产精品igao视频网 | 国产乱人无码伦av在线a | 欧美人与动性行为视频 | 精品久久久无码人妻字幂 | 欧美日韩综合一区二区三区 | 免费国产成人高清在线观看网站 | 久久久久亚洲精品男人的天堂 | 亚洲欧美日韩成人高清在线一区 | 亚洲日韩av片在线观看 | 亚洲精品国产第一综合99久久 | 人妻夜夜爽天天爽三区 | 日本精品久久久久中文字幕 | 免费观看的无遮挡av | 亚洲精品久久久久中文第一幕 | 男女爱爱好爽视频免费看 | 欧洲精品码一区二区三区免费看 | 西西人体www44rt大胆高清 | 人妻插b视频一区二区三区 | 精品成人av一区二区三区 | 亚洲国产欧美国产综合一区 | 天天综合网天天综合色 | 久久人人97超碰a片精品 | 美女黄网站人色视频免费国产 | 亚洲欧洲中文日韩av乱码 | 免费观看激色视频网站 | 国产人妻久久精品二区三区老狼 | 熟妇女人妻丰满少妇中文字幕 | 国产真实乱对白精彩久久 | 人妻无码αv中文字幕久久琪琪布 | 国产精品人人妻人人爽 | 久久亚洲国产成人精品性色 | 午夜丰满少妇性开放视频 | 伊人久久大香线焦av综合影院 | 欧美日韩一区二区三区自拍 | 亚洲小说图区综合在线 | 国模大胆一区二区三区 | 67194成是人免费无码 | 人人澡人摸人人添 | 国产亚洲精品久久久久久国模美 | 粉嫩少妇内射浓精videos | 亚洲色偷偷偷综合网 | 人人妻人人澡人人爽欧美精品 | 99re在线播放 | 日韩无码专区 | 亚洲精品鲁一鲁一区二区三区 | 全黄性性激高免费视频 | 成人片黄网站色大片免费观看 | 人妻插b视频一区二区三区 | 国产成人一区二区三区别 | 波多野结衣aⅴ在线 | 无码成人精品区在线观看 | 国产成人无码av片在线观看不卡 | 亚洲乱码国产乱码精品精 | 一本久道高清无码视频 | 久久无码中文字幕免费影院蜜桃 | 日日天干夜夜狠狠爱 | 久久精品人人做人人综合 | 亚洲熟妇自偷自拍另类 | 国产av一区二区三区最新精品 | 亚洲中文字幕无码一久久区 | 日本肉体xxxx裸交 | 人妻少妇精品无码专区二区 | 永久免费观看国产裸体美女 | 国产成人无码av在线影院 | 天干天干啦夜天干天2017 | 久久综合激激的五月天 | 中文字幕人妻丝袜二区 | 亚洲色偷偷男人的天堂 | 午夜精品久久久久久久久 | 亚洲欧洲无卡二区视頻 | 无码av岛国片在线播放 | 人妻少妇精品无码专区二区 | 99久久99久久免费精品蜜桃 | 人人妻人人澡人人爽人人精品 | 性欧美疯狂xxxxbbbb | 国产精品va在线观看无码 | 日本爽爽爽爽爽爽在线观看免 | 久久97精品久久久久久久不卡 | 中文字幕无码日韩专区 | 女人被男人爽到呻吟的视频 | 午夜性刺激在线视频免费 | 色欲av亚洲一区无码少妇 | 麻豆人妻少妇精品无码专区 | 国产又爽又黄又刺激的视频 | 久久精品99久久香蕉国产色戒 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产综合久久久久鬼色 | 日日碰狠狠躁久久躁蜜桃 | 亚洲日韩av一区二区三区中文 | 久久国产精品_国产精品 | 野狼第一精品社区 | 日本大乳高潮视频在线观看 | 无码人妻精品一区二区三区不卡 | 国产欧美亚洲精品a | 日韩欧美成人免费观看 | 久久精品一区二区三区四区 | 国内精品人妻无码久久久影院 | 欧美 日韩 亚洲 在线 | 无遮挡国产高潮视频免费观看 | 成人亚洲精品久久久久 | 亚洲码国产精品高潮在线 | 人妻与老人中文字幕 | 亚洲爆乳大丰满无码专区 | 5858s亚洲色大成网站www | 日本一本二本三区免费 | 永久黄网站色视频免费直播 | 国产精品亚洲五月天高清 | 国产极品美女高潮无套在线观看 | 国产区女主播在线观看 | 亚洲色成人中文字幕网站 | 免费人成在线视频无码 | 国产成人综合在线女婷五月99播放 | 国产成人久久精品流白浆 | 国产精品怡红院永久免费 | 激情亚洲一区国产精品 | 曰韩无码二三区中文字幕 | 国产精品久久久久影院嫩草 | 亚洲综合色区中文字幕 | 国精产品一区二区三区 | 少妇无码av无码专区在线观看 | 久久无码专区国产精品s | 97久久国产亚洲精品超碰热 | 成人亚洲精品久久久久 | 亚洲国产精品毛片av不卡在线 | 国产肉丝袜在线观看 | 又色又爽又黄的美女裸体网站 | 永久免费精品精品永久-夜色 | 亚洲乱码国产乱码精品精 | 牲欲强的熟妇农村老妇女视频 | 日日躁夜夜躁狠狠躁 | 国产真实伦对白全集 | 亚洲阿v天堂在线 | 55夜色66夜色国产精品视频 | 国产三级久久久精品麻豆三级 | 中文字幕乱妇无码av在线 | 亚洲成a人片在线观看日本 | 色 综合 欧美 亚洲 国产 | 成人免费无码大片a毛片 | 最近中文2019字幕第二页 | 免费无码午夜福利片69 | 性色av无码免费一区二区三区 | 国产精品亚洲专区无码不卡 | 色窝窝无码一区二区三区色欲 | 日韩av无码一区二区三区不卡 | 波多野结衣高清一区二区三区 | 日韩在线不卡免费视频一区 | 牛和人交xxxx欧美 | 亚洲另类伦春色综合小说 | 亚洲人成网站免费播放 | 国产香蕉97碰碰久久人人 | 国产又粗又硬又大爽黄老大爷视 | 一本大道久久东京热无码av | 亚洲色欲久久久综合网东京热 | 激情五月综合色婷婷一区二区 | 成熟妇人a片免费看网站 | av小次郎收藏 | 国产偷国产偷精品高清尤物 | 自拍偷自拍亚洲精品被多人伦好爽 | 成年美女黄网站色大免费全看 | 国产精品久久久久9999小说 | 精品国产aⅴ无码一区二区 | 中文精品无码中文字幕无码专区 | 日产精品99久久久久久 | 精品欧美一区二区三区久久久 | 亚洲国产精品无码久久久久高潮 | 人妻与老人中文字幕 | 欧美日韩久久久精品a片 | 老熟妇仑乱视频一区二区 | 亚洲最大成人网站 | 国产亚洲精品久久久久久大师 | 乱码午夜-极国产极内射 | 国内精品人妻无码久久久影院 | 久久精品中文字幕一区 | 欧美兽交xxxx×视频 | 成人无码影片精品久久久 | 乱中年女人伦av三区 | 国产 精品 自在自线 | 狂野欧美性猛交免费视频 | 思思久久99热只有频精品66 | 久久综合久久自在自线精品自 | www国产亚洲精品久久网站 | 国产另类ts人妖一区二区 | 欧美人与物videos另类 | 一本加勒比波多野结衣 | 乱人伦人妻中文字幕无码久久网 | 国内精品久久毛片一区二区 | 精品一二三区久久aaa片 | 无码乱肉视频免费大全合集 | 亚洲国产一区二区三区在线观看 | 亚洲欧美精品aaaaaa片 | 少妇性荡欲午夜性开放视频剧场 | 内射白嫩少妇超碰 | 性欧美牲交xxxxx视频 | 黑人巨大精品欧美一区二区 | 性欧美大战久久久久久久 | 人妻互换免费中文字幕 | 国产卡一卡二卡三 | 成人免费视频在线观看 | 国产精品自产拍在线观看 | 综合网日日天干夜夜久久 | 日本熟妇大屁股人妻 | 久久久久亚洲精品中文字幕 | 国产免费无码一区二区视频 | 六月丁香婷婷色狠狠久久 | 亚洲熟妇色xxxxx欧美老妇y | 97久久精品无码一区二区 | 丰满少妇弄高潮了www | 亚洲精品午夜无码电影网 | 久久精品国产大片免费观看 | 中文字幕无码热在线视频 | 粗大的内捧猛烈进出视频 | 国产亚洲精品精品国产亚洲综合 | 国产精品久久久久无码av色戒 | 午夜精品久久久久久久久 | 俄罗斯老熟妇色xxxx | 欧美亚洲日韩国产人成在线播放 | 曰韩少妇内射免费播放 | 2020久久香蕉国产线看观看 | 捆绑白丝粉色jk震动捧喷白浆 | 中文字幕精品av一区二区五区 | 国产熟妇另类久久久久 | 久久精品无码一区二区三区 | 久久人人97超碰a片精品 | 久久 国产 尿 小便 嘘嘘 | 风流少妇按摩来高潮 | 少妇性荡欲午夜性开放视频剧场 | 白嫩日本少妇做爰 | 思思久久99热只有频精品66 | 成人无码精品1区2区3区免费看 | 国产成人人人97超碰超爽8 | 国产精品嫩草久久久久 | 亚洲 欧美 激情 小说 另类 | 国内精品九九久久久精品 | 人人妻人人澡人人爽欧美精品 | 午夜免费福利小电影 | 久久这里只有精品视频9 | 精品偷拍一区二区三区在线看 | 国产在线精品一区二区三区直播 | 亚洲精品久久久久中文第一幕 | 国产综合在线观看 | 樱花草在线播放免费中文 | 欧美亚洲国产一区二区三区 | aa片在线观看视频在线播放 | 色欲人妻aaaaaaa无码 | 亚洲色www成人永久网址 | 99久久99久久免费精品蜜桃 | 无码国产乱人伦偷精品视频 | 国产小呦泬泬99精品 | 色老头在线一区二区三区 | 国产特级毛片aaaaaaa高清 | 国产亚洲精品久久久久久国模美 | 国语精品一区二区三区 | 性欧美大战久久久久久久 | 国产黄在线观看免费观看不卡 | 中文字幕亚洲情99在线 | 欧美性生交xxxxx久久久 | 精品人妻人人做人人爽 | 性色av无码免费一区二区三区 | 999久久久国产精品消防器材 | 国产三级精品三级男人的天堂 | 国产明星裸体无码xxxx视频 | 国产莉萝无码av在线播放 | 丰满少妇熟乱xxxxx视频 | 国产精品无码一区二区三区不卡 | 亚洲精品中文字幕乱码 | 性欧美大战久久久久久久 | 无码av岛国片在线播放 | 四虎国产精品免费久久 | 无码av免费一区二区三区试看 | 久久婷婷五月综合色国产香蕉 | 国产一精品一av一免费 | 人妻尝试又大又粗久久 | 精品久久综合1区2区3区激情 | 亚洲综合精品香蕉久久网 | 日韩欧美中文字幕公布 | 亚洲国产av美女网站 | av无码不卡在线观看免费 | 亚洲人成网站色7799 | 免费看少妇作爱视频 | 国产精品久久国产精品99 | 四虎影视成人永久免费观看视频 | 欧美老熟妇乱xxxxx | 免费观看的无遮挡av | 国产黑色丝袜在线播放 | 欧美精品国产综合久久 | 两性色午夜视频免费播放 | 成熟人妻av无码专区 | 人妻插b视频一区二区三区 | 国产精品久免费的黄网站 | 又紧又大又爽精品一区二区 | 精品国产麻豆免费人成网站 | 婷婷六月久久综合丁香 | 免费人成在线视频无码 | 全球成人中文在线 | 久久人人爽人人爽人人片ⅴ | 亚洲色成人中文字幕网站 | 亚洲中文无码av永久不收费 | 久久精品人人做人人综合试看 | 麻豆国产人妻欲求不满 | 1000部夫妻午夜免费 | 亚洲综合无码一区二区三区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 久久综合色之久久综合 | 国精品人妻无码一区二区三区蜜柚 | 亚洲精品国产精品乱码视色 | 国产精品久久国产三级国 | 欧美阿v高清资源不卡在线播放 | 性欧美videos高清精品 | 精品国产一区二区三区av 性色 | 性生交大片免费看女人按摩摩 | 国产成人久久精品流白浆 | 性做久久久久久久免费看 | 成熟女人特级毛片www免费 | 国产精品无套呻吟在线 | 青草视频在线播放 | 国产免费久久精品国产传媒 | 亚洲小说春色综合另类 | 自拍偷自拍亚洲精品10p | 亚洲色在线无码国产精品不卡 | 中文无码精品a∨在线观看不卡 | 久久久久成人精品免费播放动漫 | 欧美阿v高清资源不卡在线播放 | 无码av免费一区二区三区试看 | 国产av人人夜夜澡人人爽麻豆 | 亚洲а∨天堂久久精品2021 | 无码乱肉视频免费大全合集 | 蜜桃视频插满18在线观看 | 国产婷婷色一区二区三区在线 | 亚洲成av人在线观看网址 | 日日摸日日碰夜夜爽av | 久久无码中文字幕免费影院蜜桃 | 思思久久99热只有频精品66 | 领导边摸边吃奶边做爽在线观看 | 亚洲爆乳无码专区 | 亚洲中文字幕在线无码一区二区 | 日韩人妻无码中文字幕视频 | 成人无码精品1区2区3区免费看 | 欧美国产日韩久久mv | 激情内射日本一区二区三区 | 人妻有码中文字幕在线 | 国产精品美女久久久久av爽李琼 | 粉嫩少妇内射浓精videos | 精品亚洲韩国一区二区三区 | 67194成是人免费无码 | 久久精品成人欧美大片 | 久久久久亚洲精品男人的天堂 | 亚洲日本va中文字幕 | 国产亚洲精品久久久久久大师 | 亚洲中文字幕成人无码 | 55夜色66夜色国产精品视频 | 国产舌乚八伦偷品w中 | 欧美人与禽猛交狂配 | 久久无码人妻影院 | 伊人久久婷婷五月综合97色 | 精品无码一区二区三区爱欲 | 亚洲精品一区二区三区大桥未久 | 狠狠色丁香久久婷婷综合五月 | 亚洲а∨天堂久久精品2021 | 青青草原综合久久大伊人精品 | 国产精品va在线播放 | 日本一区二区三区免费高清 | 日本又色又爽又黄的a片18禁 | 亚洲一区av无码专区在线观看 | 熟妇人妻激情偷爽文 | 亚洲欧美精品aaaaaa片 | 亚洲男人av天堂午夜在 | 久久国产精品偷任你爽任你 | 亚洲国产精品一区二区第一页 | 亚洲精品www久久久 | 97资源共享在线视频 | 亚洲gv猛男gv无码男同 | 亚洲呦女专区 | 亚洲中文字幕成人无码 | 精品无码成人片一区二区98 | 无码午夜成人1000部免费视频 | 亚洲人成网站免费播放 | 亚洲国产一区二区三区在线观看 | 色欲综合久久中文字幕网 | 一本大道伊人av久久综合 | 精品成人av一区二区三区 | 国产在线精品一区二区三区直播 | 亚洲s色大片在线观看 | 精品久久久无码人妻字幂 | 国产电影无码午夜在线播放 | 亚欧洲精品在线视频免费观看 | 九九综合va免费看 | 亚洲色偷偷男人的天堂 | 欧美刺激性大交 | 麻豆蜜桃av蜜臀av色欲av | 亚洲精品无码人妻无码 | 色欲综合久久中文字幕网 | 欧美 日韩 人妻 高清 中文 | 亚洲国产欧美在线成人 | 伦伦影院午夜理论片 | 国产亚洲精品久久久闺蜜 | 午夜福利试看120秒体验区 | 久久久国产精品无码免费专区 | 亚洲码国产精品高潮在线 | 人妻少妇精品无码专区二区 | 天天综合网天天综合色 | 国产成人亚洲综合无码 | 国产亚洲日韩欧美另类第八页 | 麻豆av传媒蜜桃天美传媒 | 日韩亚洲欧美中文高清在线 | 婷婷综合久久中文字幕蜜桃三电影 | 精品无人国产偷自产在线 | 免费无码肉片在线观看 | 最近免费中文字幕中文高清百度 | 欧美国产亚洲日韩在线二区 | 国产熟女一区二区三区四区五区 | 在线播放亚洲第一字幕 | 蜜桃臀无码内射一区二区三区 | 色婷婷欧美在线播放内射 | 国产乡下妇女做爰 | 一本久久a久久精品vr综合 | 永久免费精品精品永久-夜色 | 曰韩少妇内射免费播放 | 高清无码午夜福利视频 | 综合激情五月综合激情五月激情1 | 天干天干啦夜天干天2017 | 无码av最新清无码专区吞精 | 高清国产亚洲精品自在久久 | 欧洲精品码一区二区三区免费看 | www成人国产高清内射 | 天天摸天天碰天天添 | 无码福利日韩神码福利片 | 日韩亚洲欧美精品综合 | 欧美三级a做爰在线观看 | 午夜无码人妻av大片色欲 | 一本久道高清无码视频 | 青青草原综合久久大伊人精品 | a国产一区二区免费入口 | 亚洲精品中文字幕久久久久 | 亚洲中文字幕无码一久久区 | 国产亚洲精品久久久久久 | 中文字幕av无码一区二区三区电影 | 西西人体www44rt大胆高清 | 国产成人无码午夜视频在线观看 | av无码久久久久不卡免费网站 | 成熟人妻av无码专区 | 国产成人午夜福利在线播放 | 久久精品国产日本波多野结衣 | 国产无套粉嫩白浆在线 | 国产精品久久久久影院嫩草 | 精品亚洲成av人在线观看 | 亚洲va欧美va天堂v国产综合 | 天天躁日日躁狠狠躁免费麻豆 | 久久国产精品二国产精品 | 亚洲精品成人福利网站 | 国产精品无码mv在线观看 | 最新国产麻豆aⅴ精品无码 | 国产女主播喷水视频在线观看 | 久久精品中文字幕大胸 | 成人免费无码大片a毛片 | 欧美午夜特黄aaaaaa片 | 精品欧美一区二区三区久久久 | 色婷婷久久一区二区三区麻豆 | 国内精品久久久久久中文字幕 | 日本一卡二卡不卡视频查询 | 中文字幕无线码 | 图片小说视频一区二区 | 久久视频在线观看精品 | 免费观看激色视频网站 | 偷窥日本少妇撒尿chinese | 男人的天堂2018无码 | 成人欧美一区二区三区黑人 | 欧洲精品码一区二区三区免费看 | 欧美猛少妇色xxxxx | 国产 精品 自在自线 | 大屁股大乳丰满人妻 | 国产高清av在线播放 | 亚拍精品一区二区三区探花 | 牛和人交xxxx欧美 | 四虎国产精品一区二区 | 国产偷抇久久精品a片69 | 国产免费久久久久久无码 | 国产疯狂伦交大片 | 亚洲男人av香蕉爽爽爽爽 | 98国产精品综合一区二区三区 | 丝袜足控一区二区三区 | 中文精品无码中文字幕无码专区 | 日本一区二区三区免费高清 | 欧美精品无码一区二区三区 | 欧美xxxxx精品 | 国产综合久久久久鬼色 | 色一情一乱一伦一视频免费看 | 亚洲 日韩 欧美 成人 在线观看 | 天堂а√在线中文在线 | 性欧美熟妇videofreesex | 亚洲理论电影在线观看 | 性欧美大战久久久久久久 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 中文字幕人妻丝袜二区 | 人妻有码中文字幕在线 | 日本又色又爽又黄的a片18禁 | 亚洲精品一区国产 | 无遮挡国产高潮视频免费观看 | 精品国产麻豆免费人成网站 | 黑人巨大精品欧美黑寡妇 | 99久久精品日本一区二区免费 | 成 人 网 站国产免费观看 | 久久久久久久久蜜桃 | 久久久久久亚洲精品a片成人 | 亚洲精品久久久久中文第一幕 | 久久午夜无码鲁丝片 | 一本久道高清无码视频 | 国产一区二区三区精品视频 | 精品欧洲av无码一区二区三区 | 一本精品99久久精品77 | 国产在线精品一区二区三区直播 | 免费男性肉肉影院 | 狠狠综合久久久久综合网 | 国语精品一区二区三区 | 免费中文字幕日韩欧美 | 国产午夜亚洲精品不卡 | 中文字幕无码免费久久99 | 成人综合网亚洲伊人 | 久9re热视频这里只有精品 | 国产凸凹视频一区二区 | 精品水蜜桃久久久久久久 | 日日碰狠狠丁香久燥 | 久久久精品国产sm最大网站 | 熟女少妇在线视频播放 | 日韩少妇内射免费播放 | 国产精品久久久久影院嫩草 | 99久久久无码国产精品免费 | 精品无码一区二区三区的天堂 | 无套内谢的新婚少妇国语播放 | 日本熟妇人妻xxxxx人hd | 欧美精品在线观看 | 亚洲色偷偷男人的天堂 | 日日碰狠狠丁香久燥 | aⅴ亚洲 日韩 色 图网站 播放 | 对白脏话肉麻粗话av | 国产精品久久久久久久影院 | 久久久久久久人妻无码中文字幕爆 | 亚洲人亚洲人成电影网站色 | 欧美一区二区三区 | 久久综合香蕉国产蜜臀av | 欧美日韩一区二区三区自拍 | 国产午夜手机精彩视频 | 国产人妻人伦精品1国产丝袜 | 内射欧美老妇wbb | 学生妹亚洲一区二区 | 永久黄网站色视频免费直播 | 成熟人妻av无码专区 | 99精品视频在线观看免费 | 国产内射爽爽大片视频社区在线 | 亚洲国产精品无码久久久久高潮 | 人人爽人人澡人人人妻 | 亚洲精品综合一区二区三区在线 | 亚洲爆乳无码专区 | 免费网站看v片在线18禁无码 | 国内老熟妇对白xxxxhd | 黑人巨大精品欧美黑寡妇 | 久久精品国产一区二区三区肥胖 | 国产猛烈高潮尖叫视频免费 | 亚洲中文无码av永久不收费 | 蜜桃臀无码内射一区二区三区 | 国产熟妇高潮叫床视频播放 | 风流少妇按摩来高潮 | 成人免费视频视频在线观看 免费 | 熟女少妇在线视频播放 | 桃花色综合影院 | 久久99精品久久久久久动态图 | 欧美性猛交内射兽交老熟妇 | 日本精品人妻无码77777 天堂一区人妻无码 | 国产在线精品一区二区三区直播 | 天天拍夜夜添久久精品 | 东京热男人av天堂 | 丰满少妇弄高潮了www | 亚洲成a人片在线观看无码3d | 乱中年女人伦av三区 | 蜜桃视频韩日免费播放 | 中文字幕无线码免费人妻 | 性开放的女人aaa片 | 学生妹亚洲一区二区 | 亚洲中文字幕无码中文字在线 | 麻豆国产丝袜白领秘书在线观看 | 日日橹狠狠爱欧美视频 | 狠狠色丁香久久婷婷综合五月 | 精品欧洲av无码一区二区三区 | 永久免费观看美女裸体的网站 | 成人免费无码大片a毛片 | 国产精品.xx视频.xxtv | 特大黑人娇小亚洲女 | 四虎国产精品免费久久 | 中文字幕无码日韩专区 | 1000部啪啪未满十八勿入下载 | 精品一区二区三区无码免费视频 | 蜜桃视频韩日免费播放 | 久久国内精品自在自线 | 国产麻豆精品精东影业av网站 | 中文字幕无码av波多野吉衣 | 男人的天堂2018无码 | 帮老师解开蕾丝奶罩吸乳网站 | 亚洲欧洲日本综合aⅴ在线 | 日欧一片内射va在线影院 | 久久99精品国产.久久久久 | 亚洲成在人网站无码天堂 | 精品偷自拍另类在线观看 | 清纯唯美经典一区二区 | 成人精品视频一区二区三区尤物 | 国产精品久久久久久亚洲影视内衣 | 亚洲一区二区三区在线观看网站 | 无码成人精品区在线观看 | 欧洲精品码一区二区三区免费看 | 强奷人妻日本中文字幕 | 国产成人无码av一区二区 | 免费无码一区二区三区蜜桃大 | 日日摸夜夜摸狠狠摸婷婷 | 精品无人国产偷自产在线 | 中文字幕无码日韩欧毛 | 国产精品美女久久久网av | 国产 精品 自在自线 | 人人爽人人澡人人高潮 | 久久久精品456亚洲影院 | 激情内射亚州一区二区三区爱妻 | 国产精品沙发午睡系列 | 少妇无套内谢久久久久 | 亚洲爆乳精品无码一区二区三区 | www国产精品内射老师 | 国产人成高清在线视频99最全资源 | 四虎永久在线精品免费网址 | 久久精品中文字幕大胸 | 欧美freesex黑人又粗又大 | 麻豆国产人妻欲求不满 | 东京热一精品无码av | 亚洲aⅴ无码成人网站国产app | 国产又爽又猛又粗的视频a片 | 亚洲欧洲无卡二区视頻 | 高清国产亚洲精品自在久久 | 日韩av无码中文无码电影 | 亚洲色大成网站www国产 | 久久国产精品_国产精品 | 天干天干啦夜天干天2017 | 色一情一乱一伦一区二区三欧美 | 一本精品99久久精品77 | 国产成人精品一区二区在线小狼 | 国产精品久久福利网站 | 亚洲日本va中文字幕 | 图片小说视频一区二区 | 丰满少妇熟乱xxxxx视频 | 国产午夜亚洲精品不卡下载 | 国产肉丝袜在线观看 | 无码国内精品人妻少妇 | 亚洲国产精品久久人人爱 | 欧洲欧美人成视频在线 | 亚洲呦女专区 | 天堂亚洲免费视频 | 一本大道伊人av久久综合 | 国产成人综合在线女婷五月99播放 | 国产精品久久久久影院嫩草 | 少妇高潮一区二区三区99 | 久久久久成人片免费观看蜜芽 | 天堂在线观看www | 久久综合狠狠综合久久综合88 | 亚洲色欲色欲欲www在线 | 婷婷六月久久综合丁香 | 国产综合在线观看 | 亚洲色欲久久久综合网东京热 | 国内揄拍国内精品少妇国语 | 一本久道久久综合狠狠爱 | 国产xxx69麻豆国语对白 | 亚洲 a v无 码免 费 成 人 a v | 国产人妻精品一区二区三区不卡 | 学生妹亚洲一区二区 | 99久久精品无码一区二区毛片 | 无套内射视频囯产 | 亚洲a无码综合a国产av中文 | 99久久99久久免费精品蜜桃 | 丰满诱人的人妻3 | 日韩精品乱码av一区二区 | 国产人妻大战黑人第1集 | 亚洲成a人片在线观看日本 | 国产乱码精品一品二品 | 亚洲一区二区三区含羞草 | 成在人线av无码免费 | 亚洲性无码av中文字幕 | 乱码av麻豆丝袜熟女系列 | 欧美日韩人成综合在线播放 | 成人动漫在线观看 | 大乳丰满人妻中文字幕日本 | 色综合久久久久综合一本到桃花网 | 国产精品高潮呻吟av久久 | av在线亚洲欧洲日产一区二区 | 亚洲欧美日韩综合久久久 | 日韩在线不卡免费视频一区 | 成年美女黄网站色大免费全看 | 中文字幕无码日韩专区 | 国产日产欧产精品精品app | www一区二区www免费 | 蜜桃视频插满18在线观看 | 亚洲国产欧美国产综合一区 | 人妻少妇精品久久 | 国产在线精品一区二区三区直播 | 亚洲中文字幕无码中字 | 两性色午夜免费视频 | 熟妇人妻无码xxx视频 | 国内精品一区二区三区不卡 | 清纯唯美经典一区二区 | 狠狠色丁香久久婷婷综合五月 | 亚洲啪av永久无码精品放毛片 | 亚洲色成人中文字幕网站 | 一本久久伊人热热精品中文字幕 | 亚洲 日韩 欧美 成人 在线观看 | 国产激情无码一区二区 | 少妇的肉体aa片免费 | 亚洲熟妇色xxxxx欧美老妇 | 少妇性荡欲午夜性开放视频剧场 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 亚洲人成影院在线观看 | 麻花豆传媒剧国产免费mv在线 | 中文字幕av日韩精品一区二区 | 国产精品久久久久久亚洲影视内衣 | 88国产精品欧美一区二区三区 | av无码久久久久不卡免费网站 | 精品久久久久久亚洲精品 | 中文字幕无码日韩专区 | 成 人影片 免费观看 | 澳门永久av免费网站 | 东京无码熟妇人妻av在线网址 | 日本va欧美va欧美va精品 | 亚洲国产精品成人久久蜜臀 | 成年美女黄网站色大免费视频 | 最新国产麻豆aⅴ精品无码 | 亚洲精品午夜国产va久久成人 | 午夜不卡av免费 一本久久a久久精品vr综合 | 无套内谢的新婚少妇国语播放 | 伊人久久大香线蕉亚洲 | 国产卡一卡二卡三 | 欧洲欧美人成视频在线 | 国产精品亚洲а∨无码播放麻豆 | 福利一区二区三区视频在线观看 | 成人一区二区免费视频 | 理论片87福利理论电影 | 中文字幕乱码人妻二区三区 | 国产后入清纯学生妹 | 亚洲爆乳大丰满无码专区 | 又大又黄又粗又爽的免费视频 | 男女猛烈xx00免费视频试看 | 男人的天堂av网站 | 成人性做爰aaa片免费看 | 成人无码精品1区2区3区免费看 | 亚洲精品一区国产 | 亚洲啪av永久无码精品放毛片 | 一本大道久久东京热无码av | 性开放的女人aaa片 | 纯爱无遮挡h肉动漫在线播放 | 久久精品女人天堂av免费观看 | 色综合久久久无码网中文 | 无码国产色欲xxxxx视频 | 亚洲精品无码国产 | 久久伊人色av天堂九九小黄鸭 | 亚洲色大成网站www国产 | 久久久精品国产sm最大网站 | 日韩精品无码一区二区中文字幕 | 亚洲成av人在线观看网址 | 精品人妻av区 | 色综合久久久无码中文字幕 | 婷婷丁香五月天综合东京热 | 国产精品嫩草久久久久 | 日韩精品成人一区二区三区 | 久久精品丝袜高跟鞋 | 国产亚洲精品久久久久久国模美 | 麻花豆传媒剧国产免费mv在线 | 5858s亚洲色大成网站www | 俄罗斯老熟妇色xxxx | 国产av一区二区三区最新精品 | 欧美性色19p | 男人的天堂2018无码 | 亚洲精品久久久久久一区二区 | 特黄特色大片免费播放器图片 | 久久精品人妻少妇一区二区三区 | aⅴ在线视频男人的天堂 | 国产av人人夜夜澡人人爽麻豆 | 成人三级无码视频在线观看 | 欧美人妻一区二区三区 | 久久亚洲中文字幕精品一区 | а天堂中文在线官网 | 国产精品视频免费播放 | 国产精品久久久午夜夜伦鲁鲁 | 熟妇人妻激情偷爽文 | 激情五月综合色婷婷一区二区 | 九月婷婷人人澡人人添人人爽 | 欧美成人家庭影院 | 日韩欧美中文字幕在线三区 | 欧美激情一区二区三区成人 | 国产明星裸体无码xxxx视频 | 国产网红无码精品视频 | 国产综合色产在线精品 | 久久伊人色av天堂九九小黄鸭 | 纯爱无遮挡h肉动漫在线播放 | 久久久久成人片免费观看蜜芽 | 婷婷丁香六月激情综合啪 | 一本久久伊人热热精品中文字幕 | 亚洲男人av天堂午夜在 | 国产偷抇久久精品a片69 | 中文字幕无码免费久久99 | 成人女人看片免费视频放人 | 国产精品爱久久久久久久 | 亚洲精品一区二区三区四区五区 | 日本护士毛茸茸高潮 | 亚洲日韩中文字幕在线播放 | 天天拍夜夜添久久精品大 | 夜夜影院未满十八勿进 | 乱码午夜-极国产极内射 | 成年美女黄网站色大免费全看 | 亚洲精品久久久久久久久久久 | 鲁鲁鲁爽爽爽在线视频观看 | 亚洲欧美日韩综合久久久 | 久久精品人人做人人综合 | 亚洲欧美精品aaaaaa片 | 亚洲成色在线综合网站 | 国产精品国产自线拍免费软件 | 久久天天躁夜夜躁狠狠 | 青春草在线视频免费观看 | 狠狠躁日日躁夜夜躁2020 | 亚洲国产日韩a在线播放 | 久久综合九色综合欧美狠狠 | 丰满肥臀大屁股熟妇激情视频 | 老熟女重囗味hdxx69 | 国产激情无码一区二区 | 亚洲国产精品成人久久蜜臀 | 日日橹狠狠爱欧美视频 | 狠狠色色综合网站 | 波多野结衣av一区二区全免费观看 | 亚洲一区av无码专区在线观看 | 亚洲一区av无码专区在线观看 | 精品无码av一区二区三区 | 香港三级日本三级妇三级 | 久久综合九色综合97网 | 成熟人妻av无码专区 | 亚洲国产精品美女久久久久 | 色偷偷人人澡人人爽人人模 | 成人av无码一区二区三区 | 青青青手机频在线观看 | 永久免费观看国产裸体美女 | 国产成人无码a区在线观看视频app | 精品日本一区二区三区在线观看 | 男人和女人高潮免费网站 | 亚洲国产精品毛片av不卡在线 | 一本一道久久综合久久 | 久久久精品456亚洲影院 | 好男人社区资源 | 无码精品国产va在线观看dvd | 久久午夜无码鲁丝片午夜精品 | 在线观看欧美一区二区三区 | 午夜福利电影 | 东北女人啪啪对白 | 国产特级毛片aaaaaa高潮流水 | 精品国产一区av天美传媒 | 欧美真人作爱免费视频 | 性做久久久久久久久 | 欧美熟妇另类久久久久久不卡 | 丰满人妻一区二区三区免费视频 | 久久久久se色偷偷亚洲精品av | 久久熟妇人妻午夜寂寞影院 | 狠狠亚洲超碰狼人久久 | av无码不卡在线观看免费 | 97久久国产亚洲精品超碰热 | 国产精品毛多多水多 | 国产热a欧美热a在线视频 | 成在人线av无码免观看麻豆 | 亚洲人成网站免费播放 | 人妻人人添人妻人人爱 | 国产亲子乱弄免费视频 | 成人欧美一区二区三区黑人免费 | 国产欧美亚洲精品a | 日产国产精品亚洲系列 | 国产精品久久久久7777 | 无遮挡啪啪摇乳动态图 | 永久免费观看美女裸体的网站 | 国产精品亚洲综合色区韩国 | 久久99精品久久久久婷婷 | 人人爽人人爽人人片av亚洲 | 国产在线精品一区二区三区直播 | 女人被男人爽到呻吟的视频 | 亚洲乱码日产精品bd | 久久国产精品精品国产色婷婷 | 中文字幕无码日韩专区 | 日本熟妇人妻xxxxx人hd | 亚洲а∨天堂久久精品2021 | 一二三四在线观看免费视频 | 99久久精品午夜一区二区 | 婷婷五月综合缴情在线视频 | 久久久久久久女国产乱让韩 | 欧美zoozzooz性欧美 | 久久亚洲精品中文字幕无男同 | 国产精品久久久久久久影院 | 丰满妇女强制高潮18xxxx | 日本护士xxxxhd少妇 | 亚洲大尺度无码无码专区 | 亚洲欧洲无卡二区视頻 | 日本va欧美va欧美va精品 | 日韩av激情在线观看 | 激情综合激情五月俺也去 | 精品亚洲成av人在线观看 | 国产乱子伦视频在线播放 | 无码av免费一区二区三区试看 | 欧美 丝袜 自拍 制服 另类 | 波多野42部无码喷潮在线 | 国产 精品 自在自线 | 日本丰满护士爆乳xxxx | 欧美成人家庭影院 | 国产亚洲人成在线播放 | 人妻中文无码久热丝袜 | 国产精品久久久一区二区三区 | 婷婷丁香五月天综合东京热 | 亚洲欧美国产精品专区久久 | 99精品久久毛片a片 | 午夜理论片yy44880影院 | 精品无人国产偷自产在线 | а√资源新版在线天堂 | 国产亚洲tv在线观看 | 国产免费无码一区二区视频 | 久久久av男人的天堂 | 亚洲日本va中文字幕 | av在线亚洲欧洲日产一区二区 | 日韩在线不卡免费视频一区 | 国产av一区二区三区最新精品 | 亚洲日本va中文字幕 | 丁香花在线影院观看在线播放 | 中文无码成人免费视频在线观看 | 久久精品视频在线看15 | 色老头在线一区二区三区 | 国产亚洲人成a在线v网站 | 久久久久久亚洲精品a片成人 | 久久久av男人的天堂 | 日韩欧美群交p片內射中文 | 欧美国产亚洲日韩在线二区 | 少妇性l交大片欧洲热妇乱xxx | 天天摸天天透天天添 | 亚洲精品久久久久久一区二区 | 无人区乱码一区二区三区 | 大胆欧美熟妇xx | 99久久99久久免费精品蜜桃 | 在线а√天堂中文官网 | 一本大道伊人av久久综合 | 欧美三级a做爰在线观看 | 老司机亚洲精品影院无码 | 伊人久久大香线蕉午夜 | 国内精品人妻无码久久久影院 | 中文字幕人妻丝袜二区 | 国产人妻大战黑人第1集 | 欧美 亚洲 国产 另类 | 久久综合九色综合欧美狠狠 | 性史性农村dvd毛片 | 午夜精品久久久久久久 | 免费无码av一区二区 | 亚洲另类伦春色综合小说 | 狠狠色欧美亚洲狠狠色www | 亚洲国产精华液网站w | 无码人妻黑人中文字幕 | 久久亚洲精品中文字幕无男同 | 水蜜桃色314在线观看 | 国产精品久久久久9999小说 | 日本肉体xxxx裸交 | 亚洲一区二区三区 | 日韩欧美中文字幕公布 | 性啪啪chinese东北女人 | 人妻有码中文字幕在线 | 99在线 | 亚洲 | 日本熟妇乱子伦xxxx | 一本色道久久综合狠狠躁 | 日韩无套无码精品 | 免费观看又污又黄的网站 | 中文字幕色婷婷在线视频 | 人妻体内射精一区二区三四 | 久久久久成人片免费观看蜜芽 | 性生交片免费无码看人 | 久青草影院在线观看国产 | 夜先锋av资源网站 | 成人精品一区二区三区中文字幕 | 国产小呦泬泬99精品 | 老子影院午夜伦不卡 | 大肉大捧一进一出视频出来呀 | aⅴ亚洲 日韩 色 图网站 播放 | 一本久久a久久精品亚洲 | 风流少妇按摩来高潮 | 思思久久99热只有频精品66 | 亚洲国精产品一二二线 | 日本又色又爽又黄的a片18禁 | 国产无遮挡又黄又爽免费视频 | 久久午夜无码鲁丝片秋霞 | 亚洲国产午夜精品理论片 | 成人欧美一区二区三区黑人 | 亚洲欧美精品伊人久久 | 日本饥渴人妻欲求不满 | 国产无套粉嫩白浆在线 | 麻豆国产人妻欲求不满谁演的 | 日本精品人妻无码77777 天堂一区人妻无码 | 无码人妻少妇伦在线电影 | 蜜臀av在线播放 久久综合激激的五月天 | 亚洲成a人片在线观看日本 | 亚洲精品一区三区三区在线观看 | 正在播放东北夫妻内射 | 国产特级毛片aaaaaaa高清 | 77777熟女视频在线观看 а天堂中文在线官网 | 国产成人综合色在线观看网站 | 伊人久久婷婷五月综合97色 | 亚洲国产高清在线观看视频 | 夜夜影院未满十八勿进 | 伊人久久婷婷五月综合97色 | 激情人妻另类人妻伦 | 国产午夜精品一区二区三区嫩草 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲成色在线综合网站 | 无遮无挡爽爽免费视频 | 亚洲啪av永久无码精品放毛片 | 亚洲色无码一区二区三区 | 国产性生交xxxxx无码 | 妺妺窝人体色www婷婷 | 精品国产乱码久久久久乱码 | 青青青手机频在线观看 | 激情爆乳一区二区三区 | 国内老熟妇对白xxxxhd | 亚洲熟女一区二区三区 | 最近中文2019字幕第二页 | 亚洲男女内射在线播放 | 国产精品久久久久久亚洲毛片 | 欧美老人巨大xxxx做受 | 人妻无码久久精品人妻 | 欧美熟妇另类久久久久久多毛 | 国产亚洲精品久久久久久国模美 | 又紧又大又爽精品一区二区 | 波多野结衣av一区二区全免费观看 | √8天堂资源地址中文在线 | 日韩成人一区二区三区在线观看 | 18禁黄网站男男禁片免费观看 | 久久久久亚洲精品男人的天堂 | 最近中文2019字幕第二页 | 扒开双腿疯狂进出爽爽爽视频 | 婷婷丁香六月激情综合啪 | 亚洲va中文字幕无码久久不卡 | 欧美日本免费一区二区三区 | 国产精品久久久久久亚洲毛片 | 精品无码一区二区三区的天堂 | 国产午夜无码视频在线观看 | 在线а√天堂中文官网 | 国产精品无码一区二区桃花视频 | 又粗又大又硬毛片免费看 | 久久精品国产亚洲精品 | 台湾无码一区二区 | 精品国产一区二区三区av 性色 | 日本一本二本三区免费 | 亚洲热妇无码av在线播放 | 成熟女人特级毛片www免费 | 岛国片人妻三上悠亚 | 亚洲乱亚洲乱妇50p | 黑人大群体交免费视频 | 欧洲欧美人成视频在线 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 国产精品无码永久免费888 | 久久精品女人天堂av免费观看 | 一本久久a久久精品vr综合 | 日本护士毛茸茸高潮 | 亚洲熟妇色xxxxx亚洲 | 日本精品人妻无码免费大全 | 99视频精品全部免费免费观看 | 久久精品国产大片免费观看 | 色欲久久久天天天综合网精品 | аⅴ资源天堂资源库在线 | 欧美乱妇无乱码大黄a片 | 亚洲精品美女久久久久久久 | 日本熟妇乱子伦xxxx | 秋霞成人午夜鲁丝一区二区三区 | 免费网站看v片在线18禁无码 | 久久人人爽人人爽人人片ⅴ | 极品尤物被啪到呻吟喷水 | 东京无码熟妇人妻av在线网址 | 日本一卡二卡不卡视频查询 | 国产无遮挡吃胸膜奶免费看 | 好男人社区资源 | 久久zyz资源站无码中文动漫 | 少妇性俱乐部纵欲狂欢电影 | 亚洲爆乳无码专区 | 欧美人与善在线com | 免费人成网站视频在线观看 | 无码精品国产va在线观看dvd | 午夜福利不卡在线视频 | 亚洲国产成人a精品不卡在线 | 色噜噜亚洲男人的天堂 | 欧美老人巨大xxxx做受 | 亚洲中文字幕无码中文字在线 | 亚洲欧美综合区丁香五月小说 | 成人精品天堂一区二区三区 | 亚洲精品久久久久久一区二区 | 国内综合精品午夜久久资源 | 亚洲熟女一区二区三区 | 欧美精品无码一区二区三区 | 午夜丰满少妇性开放视频 | 一区二区传媒有限公司 | 2020久久超碰国产精品最新 | 东京热一精品无码av | 中文字幕无码日韩欧毛 | 久久久久久亚洲精品a片成人 | 67194成是人免费无码 | 日韩少妇内射免费播放 | 无套内谢的新婚少妇国语播放 | 无遮挡啪啪摇乳动态图 | 日韩精品成人一区二区三区 | 99久久精品日本一区二区免费 | 久9re热视频这里只有精品 | 成人欧美一区二区三区 | 国产av一区二区精品久久凹凸 | 国产精品18久久久久久麻辣 | 亚洲爆乳精品无码一区二区三区 | 动漫av一区二区在线观看 | 欧美xxxxx精品 | 亚洲中文字幕在线观看 | 国产亚洲精品久久久久久久久动漫 | 无码福利日韩神码福利片 | 中文字幕日韩精品一区二区三区 | 老子影院午夜伦不卡 | 婷婷六月久久综合丁香 | 伊人久久大香线蕉av一区二区 | 黑人玩弄人妻中文在线 | 国产在线无码精品电影网 | 精品国产一区二区三区四区在线看 | 国内少妇偷人精品视频免费 | 7777奇米四色成人眼影 | 精品国精品国产自在久国产87 | 男人和女人高潮免费网站 | 国产亚洲精品久久久久久久久动漫 | 久久综合狠狠综合久久综合88 | 俄罗斯老熟妇色xxxx | 国产在线精品一区二区高清不卡 | 啦啦啦www在线观看免费视频 | 日韩欧美成人免费观看 | 亚洲精品综合一区二区三区在线 | 国产麻豆精品精东影业av网站 | 国产av一区二区三区最新精品 | 熟妇激情内射com | 欧美老熟妇乱xxxxx | 呦交小u女精品视频 | 欧美日韩人成综合在线播放 | 亚洲精品久久久久中文第一幕 | 丰满诱人的人妻3 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 国产精品久久久久影院嫩草 | 77777熟女视频在线观看 а天堂中文在线官网 | 欧美激情综合亚洲一二区 | 亚洲一区av无码专区在线观看 | 夜精品a片一区二区三区无码白浆 | 亚洲一区二区三区含羞草 | 久久99精品久久久久久动态图 | 乱人伦中文视频在线观看 | 无码人妻av免费一区二区三区 | 国产 精品 自在自线 | 在教室伦流澡到高潮hnp视频 | 精品欧洲av无码一区二区三区 | 天堂久久天堂av色综合 | 国产欧美精品一区二区三区 | 色 综合 欧美 亚洲 国产 | 国产精品亚洲综合色区韩国 | 丰满人妻被黑人猛烈进入 | 国产偷自视频区视频 | 影音先锋中文字幕无码 | 中文字幕乱码人妻无码久久 | 曰本女人与公拘交酡免费视频 | 极品嫩模高潮叫床 | 2020久久超碰国产精品最新 | 国产片av国语在线观看 | 人妻少妇精品久久 | 在线视频网站www色 | yw尤物av无码国产在线观看 | 九一九色国产 | 日产精品高潮呻吟av久久 | 人妻少妇精品视频专区 | 少妇人妻av毛片在线看 | 四虎4hu永久免费 | 性做久久久久久久免费看 | 大乳丰满人妻中文字幕日本 | 无码国产色欲xxxxx视频 | 爽爽影院免费观看 | 亚洲 欧美 激情 小说 另类 | 人人妻人人澡人人爽欧美一区九九 | 人妻与老人中文字幕 | 亚洲精品一区二区三区婷婷月 | 国产午夜福利100集发布 | 一区二区三区乱码在线 | 欧洲 | 国内精品人妻无码久久久影院 | 国产精品久久久 | 欧美三级a做爰在线观看 | 日本成熟视频免费视频 | 欧美 日韩 人妻 高清 中文 | 窝窝午夜理论片影院 | 又湿又紧又大又爽a视频国产 | 国产舌乚八伦偷品w中 | 国产sm调教视频在线观看 | 香蕉久久久久久av成人 | 欧美xxxx黑人又粗又长 | 久久久久久国产精品无码下载 | 午夜无码区在线观看 | 欧美老妇交乱视频在线观看 | 女人被爽到呻吟gif动态图视看 | 55夜色66夜色国产精品视频 | 欧美刺激性大交 | 久久久久久亚洲精品a片成人 | 一本色道久久综合狠狠躁 | 熟妇人妻中文av无码 | 红桃av一区二区三区在线无码av | 男女爱爱好爽视频免费看 | 青草视频在线播放 | 一本久久伊人热热精品中文字幕 | 国产农村乱对白刺激视频 | www国产精品内射老师 | 老司机亚洲精品影院无码 | 婷婷综合久久中文字幕蜜桃三电影 | 欧美国产日韩久久mv | 日韩亚洲欧美中文高清在线 | 国产色在线 | 国产 | 中文字幕人成乱码熟女app | 精品人人妻人人澡人人爽人人 | 在线天堂新版最新版在线8 | 亚洲s色大片在线观看 | 性做久久久久久久免费看 | 精品乱码久久久久久久 | 亚洲成av人片在线观看无码不卡 | 亚洲人成影院在线观看 | 国产麻豆精品一区二区三区v视界 | 天天做天天爱天天爽综合网 | 亚洲aⅴ无码成人网站国产app | 东北女人啪啪对白 | 国产精品-区区久久久狼 | 国产成人一区二区三区在线观看 | 狠狠cao日日穞夜夜穞av | 男女作爱免费网站 | 精品久久8x国产免费观看 | 亚洲成色www久久网站 | 自拍偷自拍亚洲精品被多人伦好爽 | 又黄又爽又色的视频 | 牲欲强的熟妇农村老妇女视频 | 精品久久久无码人妻字幂 | 少妇邻居内射在线 | 一二三四社区在线中文视频 | 国产激情一区二区三区 | av无码不卡在线观看免费 | 中文字幕 亚洲精品 第1页 | 少妇人妻av毛片在线看 | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲va中文字幕无码久久不卡 | 熟女少妇在线视频播放 | a片免费视频在线观看 | 青草青草久热国产精品 | 亚洲日韩精品欧美一区二区 | 日韩欧美群交p片內射中文 | 天天爽夜夜爽夜夜爽 | 日本乱人伦片中文三区 | 国产精品毛片一区二区 | 3d动漫精品啪啪一区二区中 | 欧美老妇与禽交 | 未满小14洗澡无码视频网站 | 成人精品天堂一区二区三区 | 亚洲中文字幕va福利 | 久久99国产综合精品 | 久久精品国产99精品亚洲 | 亚洲一区二区三区在线观看网站 | 一个人看的www免费视频在线观看 | 欧美怡红院免费全部视频 | 综合人妻久久一区二区精品 | 日韩人妻少妇一区二区三区 | 国产精品永久免费视频 | 欧美35页视频在线观看 | 亚洲 激情 小说 另类 欧美 | 日本一区二区三区免费高清 | 久久综合狠狠综合久久综合88 | 欧美真人作爱免费视频 | 亚洲中文字幕成人无码 | 国产亚洲精品久久久久久久 | 俺去俺来也在线www色官网 | 精品无码成人片一区二区98 | 东北女人啪啪对白 | 欧美变态另类xxxx | 理论片87福利理论电影 | 午夜丰满少妇性开放视频 | 无码吃奶揉捏奶头高潮视频 | 亚洲伊人久久精品影院 | 学生妹亚洲一区二区 | 亚洲无人区一区二区三区 | 玩弄人妻少妇500系列视频 | 国产亚洲人成a在线v网站 | 亚洲国产精品久久人人爱 | 77777熟女视频在线观看 а天堂中文在线官网 | 高潮喷水的毛片 | 国产超碰人人爽人人做人人添 | 特黄特色大片免费播放器图片 | 国产精品丝袜黑色高跟鞋 | 无码人妻精品一区二区三区不卡 | √天堂资源地址中文在线 | 四虎永久在线精品免费网址 | 精品国产麻豆免费人成网站 | 老熟妇乱子伦牲交视频 | 亚洲午夜久久久影院 | 亚洲欧洲中文日韩av乱码 | www国产亚洲精品久久久日本 | 久9re热视频这里只有精品 | 久久亚洲日韩精品一区二区三区 | 三上悠亚人妻中文字幕在线 | 伊在人天堂亚洲香蕉精品区 | 久久久久久久久蜜桃 | 爽爽影院免费观看 | 色欲综合久久中文字幕网 | 无码一区二区三区在线 | 国产午夜精品一区二区三区嫩草 | 亚洲欧美色中文字幕在线 | 精品人人妻人人澡人人爽人人 | 国产成人精品无码播放 | 久久亚洲精品中文字幕无男同 | 性欧美牲交在线视频 | 精品人妻人人做人人爽 | 中文字幕人妻丝袜二区 | 国产一区二区三区四区五区加勒比 | 欧美熟妇另类久久久久久多毛 | 欧美肥老太牲交大战 | av小次郎收藏 | 亚洲精品久久久久avwww潮水 | 亚洲熟妇自偷自拍另类 | 亚洲国产精品久久久久久 | 少妇厨房愉情理9仑片视频 | 色综合久久88色综合天天 | 青草青草久热国产精品 | 中文无码成人免费视频在线观看 | 国产精品va在线播放 | 免费无码的av片在线观看 | 丝袜 中出 制服 人妻 美腿 | 51国偷自产一区二区三区 | 国产亚洲精品久久久久久大师 | 久久人妻内射无码一区三区 | 国产真实夫妇视频 | 日韩少妇内射免费播放 | 1000部夫妻午夜免费 | 国产精品久久久av久久久 | 色综合久久久无码网中文 | 人人妻人人澡人人爽欧美精品 | 久久综合九色综合欧美狠狠 | 熟女少妇人妻中文字幕 | 无码国产乱人伦偷精品视频 | 精品亚洲成av人在线观看 | 亚洲日韩一区二区三区 | 国产精品视频免费播放 | 日本精品少妇一区二区三区 | 无套内谢的新婚少妇国语播放 | 亚洲日韩中文字幕在线播放 | 国产成人午夜福利在线播放 | 青青青手机频在线观看 | 大肉大捧一进一出好爽视频 | 人人妻人人澡人人爽欧美一区九九 | 东京无码熟妇人妻av在线网址 | 欧美国产日产一区二区 | 成人无码精品一区二区三区 | 97精品国产97久久久久久免费 | 成人精品视频一区二区三区尤物 | 亚洲区小说区激情区图片区 | 一本久久伊人热热精品中文字幕 | 亚洲国产精品美女久久久久 | 久青草影院在线观看国产 | 三上悠亚人妻中文字幕在线 | 国产农村妇女高潮大叫 | 亚洲国产精华液网站w | 亚洲欧洲中文日韩av乱码 | 激情内射亚州一区二区三区爱妻 | 婷婷五月综合缴情在线视频 | 少妇被黑人到高潮喷出白浆 | 色综合视频一区二区三区 | 成人免费视频一区二区 | 国产精品高潮呻吟av久久 | 欧美老熟妇乱xxxxx | 午夜免费福利小电影 | 国内精品人妻无码久久久影院蜜桃 | 人人妻人人澡人人爽精品欧美 | av在线亚洲欧洲日产一区二区 | 日日碰狠狠躁久久躁蜜桃 | 日本一卡二卡不卡视频查询 | 中文字幕色婷婷在线视频 | 日本爽爽爽爽爽爽在线观看免 | 日本又色又爽又黄的a片18禁 | 国产乱人偷精品人妻a片 | 天堂а√在线地址中文在线 | 欧洲极品少妇 | 国产97在线 | 亚洲 | 强伦人妻一区二区三区视频18 | 无码人中文字幕 | 99国产欧美久久久精品 | 噜噜噜亚洲色成人网站 | 欧美国产日韩亚洲中文 | 黑人巨大精品欧美黑寡妇 | 国产亚洲欧美在线专区 | 色狠狠av一区二区三区 | 国产成人无码av片在线观看不卡 | 国内精品人妻无码久久久影院 | 亚洲一区二区三区 | 97精品国产97久久久久久免费 | 欧美日本免费一区二区三区 | 亚洲 另类 在线 欧美 制服 | a片在线免费观看 | 欧美一区二区三区视频在线观看 | 国内老熟妇对白xxxxhd | 成人精品视频一区二区三区尤物 | 永久免费精品精品永久-夜色 | 国产精品久久久久久久9999 | 成人三级无码视频在线观看 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 亚洲欧美国产精品久久 | 中文亚洲成a人片在线观看 | 国产亚洲精品久久久久久久久动漫 | 内射老妇bbwx0c0ck | 一本久道久久综合狠狠爱 | 熟女少妇人妻中文字幕 | 国产免费观看黄av片 | 久激情内射婷内射蜜桃人妖 | 午夜无码人妻av大片色欲 | 国产午夜精品一区二区三区嫩草 | 日韩人妻无码一区二区三区久久99 | 亚洲欧洲日本综合aⅴ在线 | 欧美人与善在线com | 欧美熟妇另类久久久久久不卡 | 九月婷婷人人澡人人添人人爽 | 国产艳妇av在线观看果冻传媒 | 亚洲 另类 在线 欧美 制服 | av无码电影一区二区三区 | 中文字幕日韩精品一区二区三区 | 77777熟女视频在线观看 а天堂中文在线官网 | 国产成人综合色在线观看网站 | 国产熟妇另类久久久久 | 日本精品人妻无码77777 天堂一区人妻无码 | 人妻体内射精一区二区三四 | 国产亚洲精品精品国产亚洲综合 | 131美女爱做视频 | 少妇被粗大的猛进出69影院 | 人妻无码αv中文字幕久久琪琪布 | 国产黑色丝袜在线播放 | 一个人看的视频www在线 | 亚洲天堂2017无码中文 | 扒开双腿吃奶呻吟做受视频 | 国产高清不卡无码视频 | 扒开双腿疯狂进出爽爽爽视频 | 亚洲色欲色欲天天天www | 亚洲一区二区三区国产精华液 | 国产午夜亚洲精品不卡 | 国产肉丝袜在线观看 | 久久无码专区国产精品s | 亚洲色欲色欲欲www在线 | 18黄暴禁片在线观看 | 无码人妻出轨黑人中文字幕 | 自拍偷自拍亚洲精品被多人伦好爽 | 日日鲁鲁鲁夜夜爽爽狠狠 | 无码人妻av免费一区二区三区 | 伊在人天堂亚洲香蕉精品区 | 国产在线精品一区二区三区直播 | 久久久久久av无码免费看大片 | 水蜜桃亚洲一二三四在线 | 国产成人精品一区二区在线小狼 | 5858s亚洲色大成网站www | 丰满少妇女裸体bbw | 无码人妻丰满熟妇区五十路百度 | 国产无遮挡又黄又爽又色 | 国产亚洲精品久久久久久 | 国産精品久久久久久久 | 亚洲人成人无码网www国产 | 国产成人无码av一区二区 | 99久久精品无码一区二区毛片 | 国内精品久久久久久中文字幕 | 亚洲国产高清在线观看视频 | 又大又紧又粉嫩18p少妇 | 人人妻人人澡人人爽欧美一区九九 | 国产人妻久久精品二区三区老狼 | 狠狠色噜噜狠狠狠狠7777米奇 | 天堂а√在线地址中文在线 | 亚欧洲精品在线视频免费观看 | 欧美丰满熟妇xxxx | 高清国产亚洲精品自在久久 | 国产av无码专区亚洲awww | 高中生自慰www网站 | 帮老师解开蕾丝奶罩吸乳网站 | 国产人妻精品一区二区三区 | 天天爽夜夜爽夜夜爽 | 撕开奶罩揉吮奶头视频 | 老太婆性杂交欧美肥老太 | 国产麻豆精品一区二区三区v视界 | 无遮无挡爽爽免费视频 | 久久久久人妻一区精品色欧美 | v一区无码内射国产 | 国产香蕉97碰碰久久人人 | 国产日产欧产精品精品app | 性色欲网站人妻丰满中文久久不卡 | 人妻中文无码久热丝袜 | 国产舌乚八伦偷品w中 | 狠狠噜狠狠狠狠丁香五月 | 青青青手机频在线观看 | 久久精品国产99久久6动漫 | 久久精品99久久香蕉国产色戒 | 国产精品.xx视频.xxtv | 激情五月综合色婷婷一区二区 | 无码成人精品区在线观看 | 丰满人妻一区二区三区免费视频 | 99riav国产精品视频 | 啦啦啦www在线观看免费视频 | 99精品国产综合久久久久五月天 | 久久久精品欧美一区二区免费 | 国产人妻人伦精品 | 99麻豆久久久国产精品免费 | 欧美一区二区三区视频在线观看 | yw尤物av无码国产在线观看 | 亚欧洲精品在线视频免费观看 | 兔费看少妇性l交大片免费 | 国内少妇偷人精品视频 | 欧美老熟妇乱xxxxx | 麻豆蜜桃av蜜臀av色欲av | 国产熟女一区二区三区四区五区 | 亚洲中文字幕在线观看 | 国产人成高清在线视频99最全资源 | 精品国产青草久久久久福利 | 中文无码伦av中文字幕 | 红桃av一区二区三区在线无码av | 国产亲子乱弄免费视频 | 蜜桃视频韩日免费播放 | 免费中文字幕日韩欧美 | 久久人人爽人人爽人人片av高清 | 一本久久伊人热热精品中文字幕 | 伊人久久婷婷五月综合97色 | 精品水蜜桃久久久久久久 | 乱码av麻豆丝袜熟女系列 | 亚洲欧美精品伊人久久 | 成人精品一区二区三区中文字幕 | 97无码免费人妻超级碰碰夜夜 | 大屁股大乳丰满人妻 | 欧美日本免费一区二区三区 | 无码免费一区二区三区 | 宝宝好涨水快流出来免费视频 | 人人妻人人澡人人爽欧美一区 | 国产后入清纯学生妹 | 免费观看的无遮挡av | 蜜臀aⅴ国产精品久久久国产老师 | 一本久道高清无码视频 |