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

不會飛的鳥

2010年12月10日 ... 不鳥他們!!! 我要用自己開發的分布式文件系統、分布式調度系統、分布式檢索系統, 做自己的搜索引擎!!!大魚有大志!!! ---楊書童

多線程-使用條件變量

本節介紹如何使用條件變量。表 4–6 列出了可用的函數。

表 4–6 條件變量函數

操作

相關函數說明

初始化條件變量

pthread_cond_init 語法

基于條件變量阻塞

pthread_cond_wait 語法

解除阻塞特定線程

pthread_cond_signal 語法

在指定的時間之前阻塞

pthread_cond_timedwait 語法

在指定的時間間隔內阻塞

pthread_cond_reltimedwait_np 語法

解除阻塞所有線程

pthread_cond_broadcast 語法

銷毀條件變量狀態

pthread_cond_destroy 語法

 

初始化條件變量

使用 pthread_cond_init(3C) 可以將 cv 所指示的條件變量初始化為其缺省值,或者指定已經使用 pthread_condattr_init() 設置的條件變量屬性。

pthread_cond_init 語法

int	pthread_cond_init(pthread_cond_t *cv,
const pthread_condattr_t *cattr);
#include <pthread.h>
pthread_cond_t cv;
pthread_condattr_t cattr;
int ret;
/* initialize a condition variable to its default value */
ret = pthread_cond_init(&cv, NULL);
/* initialize a condition variable */
ret = pthread_cond_init(&cv, &cattr); 

cattr 設置為 NULL。將 cattr 設置為 NULL 與傳遞缺省條件變量屬性對象的地址等效,但是沒有內存開銷。對于 Solaris 線程,請參見cond_init 語法

使用 PTHREAD_COND_INITIALIZER 宏可以將以靜態方式定義的條件變量初始化為其缺省屬性。PTHREAD_COND_INITIALIZER 宏與動態分配具有 null 屬性的 pthread_cond_init() 等效,但是不進行錯誤檢查。

多個線程決不能同時初始化或重新初始化同一個條件變量。如果要重新初始化或銷毀某個條件變量,則應用程序必須確保該條件變量未被使用。

pthread_cond_init 返回值

pthread_cond_init() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cattr 指定的值無效。

EBUSY

描述:

條件變量處于使用狀態。

EAGAIN

描述:

必要的資源不可用。

ENOMEM

描述:

內存不足,無法初始化條件變量。

基于條件變量阻塞

使用 pthread_cond_wait(3C) 可以以原子方式釋放 mp 所指向的互斥鎖,并導致調用線程基于 cv 所指向的條件變量阻塞。對于 Solaris 線程,請參見cond_wait 語法

pthread_cond_wait 語法

int	pthread_cond_wait(pthread_cond_t *cv,pthread_mutex_t *mutex);
#include <pthread.h>
pthread_cond_t cv;
pthread_mutex_t mp;
int ret;
/* wait on condition variable */
ret = pthread_cond_wait(&cv, &mp); 

阻塞的線程可以通過 pthread_cond_signal()pthread_cond_broadcast() 喚醒,也可以在信號傳送將其中斷時喚醒。

不能通過 pthread_cond_wait() 的返回值來推斷與條件變量相關聯的條件的值的任何變化。必須重新評估此類條件。

pthread_cond_wait() 例程每次返回結果時調用線程都會鎖定并且擁有互斥鎖,即使返回錯誤時也是如此。

該條件獲得信號之前,該函數一直被阻塞。該函數會在被阻塞之前以原子方式釋放相關的互斥鎖,并在返回之前以原子方式再次獲取該互斥鎖。

通常,對條件表達式的評估是在互斥鎖的保護下進行的。如果條件表達式為假,線程會基于條件變量阻塞。然后,當該線程更改條件值時,另一個線程會針對條件變量發出信號。這種變化會導致所有等待該條件的線程解除阻塞并嘗試再次獲取互斥鎖。

必須重新測試導致等待的條件,然后才能從 pthread_cond_wait() 處繼續執行。喚醒的線程重新獲取互斥鎖并從 pthread_cond_wait() 返回之前,條件可能會發生變化。等待線程可能并未真正喚醒。建議使用的測試方法是,將條件檢查編寫為調用 pthread_cond_wait()while() 循環。

    pthread_mutex_lock();
while(condition_is_false)
pthread_cond_wait();
pthread_mutex_unlock();

如果有多個線程基于該條件變量阻塞,則無法保證按特定的順序獲取互斥鎖。


注 –

pthread_cond_wait() 是取消點。如果取消處于暫掛狀態,并且調用線程啟用了取消功能,則該線程會終止,并在繼續持有該鎖的情況下開始執行清除處理程序。


pthread_cond_wait 返回值

pthread_cond_wait() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cvmp 指定的值無效。

解除阻塞一個線程

對于基于 cv 所指向的條件變量阻塞的線程,使用 pthread_cond_signal(3C) 可以解除阻塞該線程。對于 Solaris 線程,請參見cond_signal 語法

pthread_cond_signal 語法

int	pthread_cond_signal(pthread_cond_t *cv);
#include <pthread.h>
pthread_cond_t cv;
int ret;
/* one condition variable is signaled */
ret = pthread_cond_signal(&cv); 

應在互斥鎖的保護下修改相關條件,該互斥鎖用于獲得信號的條件變量中。否則,可能在條件變量的測試和 pthread_cond_wait() 阻塞之間修改該變量,這會導致無限期等待。

調度策略可確定喚醒阻塞線程的順序。對于 SCHED_OTHER,將按優先級順序喚醒線程。

如果沒有任何線程基于條件變量阻塞,則調用 pthread_cond_signal() 不起作用。


示例 4–8 使用 pthread_cond_wait()pthread_cond_signal()

pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count;
decrement_count()
{
pthread_mutex_lock(&count_lock);
while (count == 0)
pthread_cond_wait(&count_nonzero, &count_lock);
count = count - 1;
pthread_mutex_unlock(&count_lock);
}
increment_count()
{
pthread_mutex_lock(&count_lock);
if (count == 0)
pthread_cond_signal(&count_nonzero);
count = count + 1;
pthread_mutex_unlock(&count_lock);
}

pthread_cond_signal 返回值

pthread_cond_signal() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cv 指向的地址非法。

示例 4–8 說明了如何使用 pthread_cond_wait()pthread_cond_signal()

在指定的時間之前阻塞

pthread_cond_timedwait(3C) 的用法與 pthread_cond_wait() 的用法基本相同,區別在于在由 abstime 指定的時間之后 pthread_cond_timedwait() 不再被阻塞。

pthread_cond_timedwait 語法

int	pthread_cond_timedwait(pthread_cond_t *cv,
pthread_mutex_t *mp, const struct timespec *abstime);
#include <pthread.h>
#include <time.h>
pthread_cond_t cv;
pthread_mutex_t mp;
timestruct_t abstime;
int ret;
/* wait on condition variable */
ret = pthread_cond_timedwait(&cv, &mp, &abstime); 

pthread_cond_timewait() 每次返回時調用線程都會鎖定并且擁有互斥鎖,即使 pthread_cond_timedwait() 返回錯誤時也是如此。 對于 Solaris 線程,請參見cond_timedwait 語法

pthread_cond_timedwait() 函數會一直阻塞,直到該條件獲得信號,或者最后一個參數所指定的時間已過為止。


注 –

pthread_cond_timedwait() 也是取消點。



示例 4–9 計時條件等待

pthread_timestruc_t to;
pthread_mutex_t m;
pthread_cond_t c;
...
pthread_mutex_lock(&m);
to.tv_sec = time(NULL) + TIMEOUT;
to.tv_nsec = 0;
while (cond == FALSE) {
err = pthread_cond_timedwait(&c, &m, &to);
if (err == ETIMEDOUT) {
/* timeout, do something */
break;
}
}
pthread_mutex_unlock(&m);

pthread_cond_timedwait 返回值

pthread_cond_timedwait() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cvabstime 指向的地址非法。

ETIMEDOUT

描述:

abstime 指定的時間已過。

超時會指定為當天時間,以便在不重新計算值的情況下高效地重新測試條件,如示例 4–9 中所示。

在指定的時間間隔內阻塞

pthread_cond_reltimedwait_np(3C) 的用法與 pthread_cond_timedwait() 的用法基本相同,唯一的區別在于 pthread_cond_reltimedwait_np() 會采用相對時間間隔而不是將來的絕對時間作為其最后一個參數的值。

pthread_cond_reltimedwait_np 語法

int  pthread_cond_reltimedwait_np(pthread_cond_t *cv,
pthread_mutex_t *mp,
const struct timespec *reltime);
#include <pthread.h>
#include <time.h>
pthread_cond_t cv;
pthread_mutex_t mp;
timestruct_t reltime;
int ret;
/* wait on condition variable */
ret = pthread_cond_reltimedwait_np(&cv, &mp, &reltime); 

pthread_cond_reltimedwait_np() 每次返回時調用線程都會鎖定并且擁有互斥鎖,即使 pthread_cond_reltimedwait_np() 返回錯誤時也是如此。對于 Solaris 線程,請參見 cond_reltimedwait(3C)pthread_cond_reltimedwait_np() 函數會一直阻塞,直到該條件獲得信號,或者最后一個參數指定的時間間隔已過為止。


注 –

pthread_cond_reltimedwait_np() 也是取消點。


pthread_cond_reltimedwait_np 返回值

pthread_cond_reltimedwait_np() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cvreltime 指示的地址非法。

ETIMEDOUT

描述:

reltime 指定的時間間隔已過。

解除阻塞所有線程

對于基于 cv 所指向的條件變量阻塞的線程,使用 pthread_cond_broadcast(3C) 可以解除阻塞所有這些線程,這由 pthread_cond_wait() 來指定。

pthread_cond_broadcast 語法

int	pthread_cond_broadcast(pthread_cond_t *cv);
#include <pthread.h>
pthread_cond_t cv;
int ret;
/* all condition variables are signaled */
ret = pthread_cond_broadcast(&cv); 

如果沒有任何線程基于該條件變量阻塞,則調用 pthread_cond_broadcast() 不起作用。對于 Solaris 線程,請參見cond_broadcast 語法

由于 pthread_cond_broadcast() 會導致所有基于該條件阻塞的線程再次爭用互斥鎖,因此請謹慎使用 pthread_cond_broadcast()。例如,通過使用 pthread_cond_broadcast(),線程可在資源釋放后爭用不同的資源量,如示例 4–10 中所示。


示例 4–10 條件變量廣播

pthread_mutex_t rsrc_lock;
pthread_cond_t rsrc_add;
unsigned int resources;
get_resources(int amount)
{
pthread_mutex_lock(&rsrc_lock);
while (resources < amount) {
pthread_cond_wait(&rsrc_add, &rsrc_lock);
}
resources -= amount;
pthread_mutex_unlock(&rsrc_lock);
}
add_resources(int amount)
{
pthread_mutex_lock(&rsrc_lock);
resources += amount;
pthread_cond_broadcast(&rsrc_add);
pthread_mutex_unlock(&rsrc_lock);
}

請注意,在 add_resources() 中,首先更新 resources 還是首先在互斥鎖中調用 pthread_cond_broadcast() 無關緊要。

應在互斥鎖的保護下修改相關條件,該互斥鎖用于獲得信號的條件變量中。否則,可能在條件變量的測試和 pthread_cond_wait() 阻塞之間修改該變量,這會導致無限期等待。

pthread_cond_broadcast 返回值

pthread_cond_broadcast() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cv 指示的地址非法。

銷毀條件變量狀態

使用 pthread_cond_destroy(3C) 可以銷毀與 cv 所指向的條件變量相關聯的任何狀態。對于 Solaris 線程,請參見cond_destroy 語法

pthread_cond_destroy 語法

int	pthread_cond_destroy(pthread_cond_t *cv);
#include <pthread.h>
pthread_cond_t cv;
int ret;
/* Condition variable is destroyed */
ret = pthread_cond_destroy(&cv); 

請注意,沒有釋放用來存儲條件變量的空間。

pthread_cond_destroy 返回值

pthread_cond_destroy() 在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述:

cv 指定的值無效。

喚醒丟失問題

如果線程未持有與條件相關聯的互斥鎖,則調用 pthread_cond_signal()pthread_cond_broadcast() 會產生喚醒丟失錯誤。

滿足以下所有條件時,即會出現喚醒丟失問題:

  • 一個線程調用 pthread_cond_signal()pthread_cond_broadcast()

  • 另一個線程已經測試了該條件,但是尚未調用 pthread_cond_wait()

  • 沒有正在等待的線程

    信號不起作用,因此將會丟失

僅當修改所測試的條件但未持有與之相關聯的互斥鎖時,才會出現此問題。只要僅在持有關聯的互斥鎖同時修改所測試的條件,即可調用 pthread_cond_signal()pthread_cond_broadcast(),而無論這些函數是否持有關聯的互斥鎖。

生成方和使用者問題

并發編程中收集了許多標準的眾所周知的問題,生成方和使用者問題只是其中的一個問題。此問題涉及到一個大小限定的緩沖區和兩類線程(生成方和使用者),生成方將項放入緩沖區中,然后使用者從緩沖區中取走項。

生成方必須在緩沖區中有可用空間之后才能向其中放置內容。使用者必須在生成方向緩沖區中寫入之后才能從中提取內容。

條件變量表示一個等待某個條件獲得信號的線程隊列。

示例 4–11 中包含兩個此類隊列。一個隊列 (less) 針對生成方,用于等待緩沖區中出現空位置。另一個隊列 (more) 針對使用者,用于等待從緩沖槽位的空位置中提取其中包含的信息。該示例中還包含一個互斥鎖,因為描述該緩沖區的數據結構一次只能由一個線程訪問。


示例 4–11 生成方和使用者的條件變量問題

typedef struct {
char buf[BSIZE];
int occupied;
int nextin;
int nextout;
pthread_mutex_t mutex;
pthread_cond_t more;
pthread_cond_t less;
} buffer_t;
buffer_t buffer;

示例 4–12 中所示,生成方線程獲取該互斥鎖以保護 buffer 數據結構,然后,緩沖區確定是否有空間可用于存放所生成的項。如果沒有可用空間,生成方線程會調用 pthread_cond_wait()pthread_cond_wait() 會導致生成方線程連接正在等待 less 條件獲得信號的線程隊列。less 表示緩沖區中的可用空間。

與此同時,在調用 pthread_cond_wait() 的過程中,該線程會釋放互斥鎖的鎖定。正在等待的生成方線程依賴于使用者線程在條件為真時發出信號,如示例 4–12 中所示。該條件獲得信號時,將會喚醒等待 less 的第一個線程。但是,該線程必須再次鎖定互斥鎖,然后才能從 pthread_cond_wait() 返回。

獲取互斥鎖可確保該線程再次以獨占方式訪問緩沖區的數據結構。該線程隨后必須檢查緩沖區中是否確實存在可用空間。如果空間可用,該線程會向下一個可用的空位置中進行寫入。

與此同時,使用者線程可能正在等待項出現在緩沖區中。這些線程正在等待條件變量 more。剛在緩沖區中存儲內容的生成方線程會調用 pthread_cond_signal() 以喚醒下一個正在等待的使用者。如果沒有正在等待的使用者,此調用將不起作用。

最后,生成方線程會解除鎖定互斥鎖,從而允許其他線程處理緩沖區的數據結構。


示例 4–12 生成方和使用者問題:生成方

void producer(buffer_t *b, char item)
{
pthread_mutex_lock(&b->mutex);
while (b->occupied >= BSIZE)
pthread_cond_wait(&b->less, &b->mutex);
assert(b->occupied < BSIZE);
b->buf[b->nextin++] = item;
b->nextin %= BSIZE;
b->occupied++;
/* now: either b->occupied < BSIZE and b->nextin is the index
of the next empty slot in the buffer, or
b->occupied == BSIZE and b->nextin is the index of the
next (occupied) slot that will be emptied by a consumer
(such as b->nextin == b->nextout) */
pthread_cond_signal(&b->more);
pthread_mutex_unlock(&b->mutex);
}

請注意 assert() 語句的用法。除非在編譯代碼時定義了 NDEBUG,否則 assert() 在其參數的計算結果為真(非零)時將不執行任何操作。如果參數的計算結果為假(零),則該程序會中止。在多線程程序中,此類斷言特別有用。如果斷言失敗,assert() 會立即指出運行時問題。assert() 還有另一個作用,即提供有用的注釋。

/* now: either b->occupied ... 開頭的注釋最好以斷言形式表示,但是由于語句過于復雜,無法用布爾值表達式來表示,因此將用英語表示。

斷言和注釋都是不變量的示例。這些不變量是邏輯語句,在程序正常執行時不應將其聲明為假,除非是線程正在修改不變量中提到的一些程序變量時的短暫修改過程中。當然,只要有線程執行語句,斷言就應當為真。

使用不變量是一種極為有用的方法。即使沒有在程序文本中聲明不變量,在分析程序時也應將其視為不變量。

每次線程執行包含注釋的代碼時,生成方代碼中表示為注釋的不變量始終為真。如果將此注釋移到緊挨 mutex_unlock() 的后面,則注釋不一定仍然為真。如果將此注釋移到緊跟 assert() 之后的位置,則注釋仍然為真。

因此,不變量可用于表示一個始終為真的屬性,除非一個生成方或一個使用者正在更改緩沖區的狀態。線程在互斥鎖的保護下處理緩沖區時,該線程可能會暫時聲明不變量為假。但是,一旦線程結束對緩沖區的操作,不變量即會恢復為真。

示例 4–13 給出了使用者的代碼。該邏輯流程與生成方的邏輯流程相對稱。


示例 4–13 生成方和使用者問題:使用者

char consumer(buffer_t *b)
{
char item;
pthread_mutex_lock(&b->mutex);
while(b->occupied <= 0)
pthread_cond_wait(&b->more, &b->mutex);
assert(b->occupied > 0);
item = b->buf[b->nextout++];
b->nextout %= BSIZE;
b->occupied--;
/* now: either b->occupied > 0 and b->nextout is the index
of the next occupied slot in the buffer, or
b->occupied == 0 and b->nextout is the index of the next
(empty) slot that will be filled by a producer (such as
b->nextout == b->nextin) */
pthread_cond_signal(&b->less);
pthread_mutex_unlock(&b->mutex);
return(item);
}

posted on 2009-01-12 13:53 不會飛的鳥 閱讀(1492) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   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>
            老牛国产精品一区的观看方式| 欧美日韩国产不卡| 国产真实久久| 欧美日韩免费高清一区色橹橹| 欧美影院久久久| 国产一区二区黄色| 伊人久久综合| 久久国产88| 在线精品视频一区二区三四| 老**午夜毛片一区二区三区| 亚洲美女在线视频| 欧美暴力喷水在线| 亚洲丝袜av一区| 中国女人久久久| 好吊色欧美一区二区三区视频| 欧美va亚洲va国产综合| 亚洲欧美久久久久一区二区三区| 久久天堂国产精品| 国产精品99久久久久久白浆小说| 免费在线一区二区| 欧美一区二区三区在线观看| 欧美在线视频一区二区三区| 久久一区二区三区av| 另类专区欧美制服同性| 一区二区三区高清视频在线观看| 午夜免费电影一区在线观看| 一区二区日韩伦理片| 久久久久国产精品一区| 午夜在线成人av| 欧美精品在线看| 欧美激情欧美激情在线五月| 国产日韩欧美91| 在线视频亚洲一区| 一区二区欧美激情| 欧美成人一区二区三区在线观看 | 日韩视频在线观看一区二区| 性欧美8khd高清极品| 亚洲一区二区三区中文字幕| 免费中文日韩| 欧美高清在线观看| 狠狠色丁香婷婷综合久久片| 亚洲欧美制服中文字幕| 亚洲午夜视频| 欧美激情一区二区三区全黄 | 欧美久久99| 亚洲福利av| 国产亚洲欧美一区| 欧美一区二区视频97| 欧美一区二区三区喷汁尤物| 国产精品美女久久久免费| 99re6热在线精品视频播放速度 | 欧美一区二区三区视频在线| 欧美一区二区三区精品电影| 国产日产亚洲精品| 欧美在线免费看| 狼狼综合久久久久综合网| 影音先锋成人资源站| 久久久久久午夜| 欧美黄免费看| 亚洲精品免费看| 欧美激情影音先锋| 亚洲高清一区二| 欧美va天堂| 99精品视频免费观看视频| 亚洲一区黄色| 国产亚洲va综合人人澡精品| 久久精品亚洲国产奇米99| 可以看av的网站久久看| 亚洲高清中文字幕| 欧美激情综合亚洲一二区| 亚洲精品在线观| 亚洲淫片在线视频| 国产农村妇女毛片精品久久麻豆| 久久国产综合精品| 欧美黄色一区二区| 一区二区欧美在线观看| 国产精品影片在线观看| 久久久久99精品国产片| 亚洲观看高清完整版在线观看| 在线视频欧美日韩| 国产三级欧美三级日产三级99| 久久亚洲风情| 99国产精品99久久久久久粉嫩| 欧美一区二区国产| 亚洲国产日韩在线| 国产精品国产自产拍高清av王其| 欧美一级一区| 亚洲精品久久久久中文字幕欢迎你| 亚洲影院色无极综合| 合欧美一区二区三区| 欧美精品免费观看二区| 亚洲欧美日韩天堂| 亚洲电影下载| 久久er精品视频| 亚洲精品视频一区| 国产欧美视频一区二区三区| 免费视频久久| 性欧美大战久久久久久久免费观看 | 亚洲风情在线资源站| 香蕉久久夜色精品国产| 亚洲人在线视频| 国产有码在线一区二区视频| 欧美成人第一页| 久久成人精品无人区| 99精品视频免费| 亚洲高清电影| 久久男人资源视频| 亚洲视频在线观看视频| 亚洲电影免费观看高清完整版在线观看 | 国产精品第一区| 麻豆av一区二区三区久久| 亚洲在线电影| aa级大片欧美三级| 亚洲国产成人精品久久| 久久久午夜精品| 午夜在线一区| 亚洲性色视频| 亚洲免费观看高清完整版在线观看熊| 国产午夜精品久久| 国产精品久久久久久久久久三级| 欧美国产第一页| 小嫩嫩精品导航| 欧美一区二区三区日韩视频| 国产一区二区精品在线观看| 欧美色欧美亚洲另类二区| 女女同性精品视频| 久久久人成影片一区二区三区观看| 亚洲在线成人精品| 中日韩男男gay无套| 亚洲精品欧美日韩| 亚洲激情啪啪| 亚洲国产精品成人| 欧美成人精品在线视频| 久久夜色精品国产欧美乱极品| 欧美一区二区高清| 欧美综合国产| 久久精品二区| 久久精品av麻豆的观看方式 | 欧美激情日韩| 欧美成人精品不卡视频在线观看| 久久日韩精品| 免费不卡中文字幕视频| 欧美88av| 欧美精品午夜| 欧美午夜一区二区福利视频| 国产精品v日韩精品| 国产精品人成在线观看免费| 国产精品久久久久久亚洲调教| 国产精品乱看| 国产一区二区日韩精品| 国内一区二区三区在线视频| 国产亚洲美州欧州综合国| 国产一区二区三区久久精品| 国产自产v一区二区三区c| 一区二区在线视频播放| 亚洲激情第一页| 一本色道久久综合精品竹菊| 亚洲午夜免费福利视频| 欧美在线1区| 麻豆成人精品| 亚洲日本成人| 亚洲性图久久| 久久久精品一区| 欧美日韩精品久久久| 国产精品久久国产愉拍| 国产亚洲精品aa| 亚洲黑丝在线| 亚洲欧美日韩成人| 老司机午夜精品| 日韩视频国产视频| 亚洲欧美另类国产| 久久久视频精品| 欧美人成免费网站| 国产日韩专区| 日韩一区二区电影网| 欧美一区午夜视频在线观看| 蘑菇福利视频一区播放| 亚洲精品视频在线| 欧美一区综合| 欧美日韩你懂的| 激情六月婷婷久久| 亚洲午夜av电影| 免费人成网站在线观看欧美高清| 日韩一级在线观看| 久久婷婷丁香| 国产精品午夜在线观看| 最新中文字幕亚洲| 久久精品成人一区二区三区蜜臀| 亚洲国产精品第一区二区三区| 亚洲欧美视频一区| 欧美久久一级| 在线观看亚洲视频| 先锋亚洲精品| 亚洲免费播放| 免费看亚洲片| 国产亚洲精品综合一区91| 一区二区三区成人| 麻豆成人在线观看| 亚洲欧美日韩综合| 欧美午夜精彩|