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

巢穴

about:blank

【轉(zhuǎn)】線程同步-自旋鎖與Mutex/信號(hào)量的區(qū)別和聯(lián)系

POSIX threads(簡(jiǎn)稱Pthreads)是在多核平臺(tái)上進(jìn)行并行編程的一套常用的API。線程同步(Thread Synchronization)是并行編程中非常重要的通訊手段,其中最典型的應(yīng)用就是用Pthreads提供的鎖機(jī)制(lock)來對(duì)多個(gè)線程之間共 享的臨界區(qū)(Critical Section)進(jìn)行保護(hù)(另一種常用的同步機(jī)制是barrier)。

Pthreads提供了多種鎖機(jī)制:
(1) Mutex(互斥量):pthread_mutex_***
(2) Spin lock(自旋鎖):pthread_spin_***
(3) Condition Variable(條件變量):pthread_con_***
(4) Read/Write lock(讀寫鎖):pthread_rwlock_***

Pthreads提供的Mutex鎖操作相關(guān)的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);

Pthreads提供的與Spin Lock鎖操作相關(guān)的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

從實(shí)現(xiàn)原理上來講,Mutex屬于sleep-waiting類型的鎖。例如在一個(gè)雙核的機(jī)器上有兩個(gè)線程(線程A和線程B),它們分別運(yùn)行在Core0和Core1上。假設(shè)線程A想要通過pthread_mutex_lock操作去得到一個(gè)臨界區(qū)的鎖,而此時(shí)這個(gè)鎖正被線程B所持有,那么線程A就會(huì)被阻塞(blocking),Core0 會(huì)在此時(shí)進(jìn)行上下文切換(Context Switch)將線程A置于等待隊(duì)列中,此時(shí)Core0就可以運(yùn)行其他的任務(wù)(例如另一個(gè)線程C)而不必進(jìn)行忙等待。而Spin lock則不然,它屬于busy-waiting類型的鎖,如果線程A是使用pthread_spin_lock操作去請(qǐng)求鎖,那么線程A就會(huì)一直在 Core0上進(jìn)行忙等待并不停的進(jìn)行鎖請(qǐng)求,直到得到這個(gè)鎖為止。

如果大家去查閱Linux glibc中對(duì)pthreads API的實(shí)現(xiàn)NPTL(Native POSIX Thread Library) 的源碼的話(使用”getconf GNU_LIBPTHREAD_VERSION”命令可以得到我們系統(tǒng)中NPTL的版本號(hào)),就會(huì)發(fā)現(xiàn)pthread_mutex_lock()操作如果沒有鎖成功的話就會(huì)調(diào)用system_wait()的系統(tǒng)調(diào)用并將當(dāng)前線程加入該mutex的等待隊(duì)列里。而spin lock則可以理解為在一個(gè)while(1)循環(huán)中用內(nèi)嵌的匯編代碼實(shí)現(xiàn)的鎖操作(印象中看過一篇論文介紹說在linux內(nèi)核中spin lock操作只需要兩條CPU指令,解鎖操作只用一條指令就可以完成)。有興趣的朋友可以參考另一個(gè)名為sanos的微內(nèi)核中pthreds API的實(shí)現(xiàn):mutex.c spinlock.c,盡管與NPTL中的代碼實(shí)現(xiàn)不盡相同,但是因?yàn)樗膶?shí)現(xiàn)非常簡(jiǎn)單易懂,對(duì)我們理解spin lock和mutex的特性還是很有幫助的。

那么在實(shí)際編程中mutex和spin lcok哪個(gè)的性能更好呢?我們知道spin lock在Linux內(nèi)核中有非常廣泛的利用,那么這是不是說明spin lock的性能更好呢?下面讓我們來用實(shí)際的代碼測(cè)試一下(請(qǐng)確保你的系統(tǒng)中已經(jīng)安裝了最近的g++)。

查看源代碼打印幫助001 // Name: spinlockvsmutex1.cc  

002 // Source: [url]http://www.alexonlinux.com/pthread-mutex-vs-pthread-spinlock[/url]  

003 // Compiler(<FONT style="BACKGROUND-COLOR: #00ffff">spin lock</FONT> version): g++ -o spin_version -DUSE_SPINLOCK spinlockvsmutex1.cc -lpthread  

004 // Compiler(mutex version): g++ -o mutex_version spinlockvsmutex1.cc -lpthread  

005 #include <stdio.h>  

006 #include <unistd.h>  

007 #include <sys/syscall.h>  

008 #include <errno.h>  

009 #include <sys/time.h>  

010 #include <list>  

011 #include <pthread.h>  

012   

013 #define LOOPS 50000000  

014   

015 using namespace std;  

016   

017 list<int> the_list;  

018   

019 #ifdef USE_SPINLOCK  

020 pthread_spinlock_t spinlock;  

021 #else  

022 pthread_mutex_t mutex;  

023 #endif  

024   

025 //Get the thread id  

026 pid_t gettid() { return syscall( __NR_gettid ); }  

027   

028 void *consumer(void *ptr)  

029 {  

030     int i;  

031   

032     printf("Consumer TID %lun", (unsigned long)gettid());  

033   

034     while (1)  

035     {  

036 #ifdef USE_SPINLOCK  

037         pthread_spin_lock(&spinlock);  

038 #else  

039         pthread_mutex_lock(&mutex);  

040 #endif  

041   

042         if (the_list.empty())  

043         {  

044 #ifdef USE_SPINLOCK  

045             pthread_spin_unlock(&spinlock);  

046 #else  

047             pthread_mutex_unlock(&mutex);  

048 #endif  

049             break;  

050         }  

051   

052         i = the_list.front();  

053         the_list.pop_front();  

054   

055 #ifdef USE_SPINLOCK  

056         pthread_spin_unlock(&spinlock);  

057 #else  

058         pthread_mutex_unlock(&mutex);  

059 #endif  

060     }  

061   

062     return NULL;  

063 }  

064   

065 int main()  

066 {  

067     int i;  

068     pthread_t thr1, thr2;  

069     struct timeval tv1, tv2;  

070   

071 #ifdef USE_SPINLOCK  

072     pthread_spin_init(&spinlock, 0);  

073 #else  

074     pthread_mutex_init(&mutex, NULL);  

075 #endif  

076   

077     // Creating the list content...  

078     for (i = 0; i < LOOPS; i++)  

079         the_list.push_back(i);  

080   

081     // Measuring time before starting the threads...  

082     gettimeofday(&tv1, NULL);  

083   

084     pthread_create(&thr1, NULL, consumer, NULL);  

085     pthread_create(&thr2, NULL, consumer, NULL);  

086   

087     pthread_join(thr1, NULL);  

088     pthread_join(thr2, NULL);  

089   

090     // Measuring time after threads finished...  

091     gettimeofday(&tv2, NULL);  

092   

093     if (tv1.tv_usec > tv2.tv_usec)  

094     {  

095         tv2.tv_sec--;  

096         tv2.tv_usec += 1000000;  

097     }  

098   

099     printf("Result - %ld.%ldn", tv2.tv_sec - tv1.tv_sec,  

100         tv2.tv_usec - tv1.tv_usec);  

101   

102 #ifdef USE_SPINLOCK  

103     pthread_spin_destroy(&spinlock);  

104 #else  

105     pthread_mutex_destroy(&mutex);  

106 #endif  

107   

108     return 0;  

109 }

該程序運(yùn)行過程如下:主線程先初始化一個(gè)list結(jié)構(gòu),并根據(jù)LOOPS的值將對(duì)應(yīng)數(shù)量的entry插入該list,之后創(chuàng)建兩個(gè)新線程,它們都執(zhí)行consumer()這個(gè)任務(wù)。兩個(gè)被創(chuàng)建的新線程同時(shí)對(duì)這個(gè)list進(jìn)行pop操作。主線程會(huì)計(jì)算從創(chuàng)建兩個(gè)新線程到兩個(gè)新線程結(jié)束之間所用的時(shí)間,輸出為下文中的”Result “。

測(cè)試機(jī)器參數(shù):
Ubuntu 9.04 X86_64
Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
4.0 GB Memory

從下面是測(cè)試結(jié)果:

查看源代碼打印幫助01 pxcwan@pxcwan-desktop:~/Workspace/mutex$ g++ -o spin_version -DUSE_SPINLOCK spinvsmutex1.cc -lpthread  

02 pxcwan@pxcwan-desktop:~/Workspace/mutex$ g++ -o mutex_version spinvsmutex1.cc -lpthread  

03 pxcwan@pxcwan-desktop:~/Workspace/mutex$ time ./spin_version  

04 Consumer TID 5520  

05 Consumer TID 5521  

06 Result - 5.888750  

07   

08 real    0m10.918s  

09 user    0m15.601s  

10 sys    0m0.804s  

11   

12 pxcwan@pxcwan-desktop:~/Workspace/mutex$ time ./mutex_version  

13 Consumer TID 5691  

14 Consumer TID 5692  

15 Result - 9.116376  

16   

17 real    0m14.031s  

18 user    0m12.245s  

19 sys    0m4.368s

可以看見spin lock的版本在該程序中表現(xiàn)出來的性能更好。另外值得注意的是sys時(shí)間,mutex版本花費(fèi)了更多的系統(tǒng)調(diào)用時(shí)間,這就是因?yàn)閙utex會(huì)在鎖沖突時(shí)調(diào)用system wait造成的。

但是,是不是說spin lock就一定更好了呢?讓我們?cè)賮砜匆粋€(gè)鎖沖突程度非常劇烈的實(shí)例程序:

查看源代碼打印幫助01 //Name: svm2.c  

02 //Source: [url]http://www.solarisinternals.com/wiki/index.php/DTrace_Topics_Locks[/url]  

03 //Compile(<FONT style="BACKGROUND-COLOR: #00ffff">spin lock</FONT> version): gcc -o spin -DUSE_SPINLOCK svm2.c -lpthread  

04 //Compile(mutex version): gcc -o mutex svm2.c -lpthread  

05 #include <stdio.h>  

06 #include <stdlib.h>  

07 #include <pthread.h>  

08 #include <sys/syscall.h>  

09   

10 #define        THREAD_NUM     2  

11   

12 pthread_t g_thread[THREAD_NUM];  

13 #ifdef USE_SPINLOCK  

14 pthread_spinlock_t g_spin;  

15 #else  

16 pthread_mutex_t g_mutex;  

17 #endif  

18 __uint64_t g_count;  

19   

20 pid_t gettid()  

21 {  

22     return syscall(SYS_gettid);  

23 }  

24   

25 void *run_amuck(void *arg)  

26 {  

27        int i, j;  

28   

29        printf("Thread %lu started.n", (unsigned long)gettid());  

30   

31        for (i = 0; i < 10000; i++) {  

32 #ifdef USE_SPINLOCK  

33            pthread_spin_lock(&g_spin);  

34 #else  

35                pthread_mutex_lock(&g_mutex);  

36 #endif  

37                for (j = 0; j < 100000; j++) {  

38                        if (g_count++ == 123456789)  

39                                printf("Thread %lu wins!n", (unsigned long)gettid());  

40                }  

41 #ifdef USE_SPINLOCK  

42            pthread_spin_unlock(&g_spin);  

43 #else  

44                pthread_mutex_unlock(&g_mutex);  

45 #endif  

46        }  

47   

48        printf("Thread %lu finished!n", (unsigned long)gettid());  

49   

50        return (NULL);  

51 }  

52   

53 int main(int argc, char *argv[])  

54 {  

55        int i, threads = THREAD_NUM;  

56   

57        printf("Creating %d threads...n", threads);  

58 #ifdef USE_SPINLOCK  

59        pthread_spin_init(&g_spin, 0);  

60 #else  

61        pthread_mutex_init(&g_mutex, NULL);  

62 #endif  

63        for (i = 0; i < threads; i++)  

64                pthread_create(&g_thread[i], NULL, run_amuck, (void *) i);  

65   

66        for (i = 0; i < threads; i++)  

67                pthread_join(g_thread[i], NULL);  

68   

69        printf("Done.n");  

70   

71        return (0);  

72 }

這個(gè)程序的特征就是臨界區(qū)非常大,這樣兩個(gè)線程的鎖競(jìng)爭(zhēng)會(huì)非常的劇烈。當(dāng)然這個(gè)是一個(gè)極端情況,實(shí)際應(yīng)用程序中臨界區(qū)不會(huì)如此大,鎖競(jìng)爭(zhēng)也不會(huì)如此激烈。測(cè)試結(jié)果顯示mutex版本性能更好:

查看源代碼打印幫助01 pxcwan@pxcwan-desktop:~/Workspace/mutex$ time ./spin  

02 Creating 2 threads...  

03 Thread 31796 started.  

04 Thread 31797 started.  

05 Thread 31797 wins!  

06 Thread 31797 finished!  

07 Thread 31796 finished!  

08 Done.  

09   

10 real    0m5.748s  

11 user    0m10.257s  

12 sys    0m0.004s  

13   

14 pxcwan@pxcwan-desktop:~/Workspace/mutex$ time ./mutex  

15 Creating 2 threads...  

16 Thread 31801 started.  

17 Thread 31802 started.  

18 Thread 31802 wins!  

19 Thread 31802 finished!  

20 Thread 31801 finished!  

21 Done.  

22   

23 real    0m4.823s  

24 user    0m4.772s  

25 sys    0m0.032s

另外一個(gè)值得注意的細(xì)節(jié)是spin lock耗費(fèi)了更多的user time。這就是因?yàn)閮蓚€(gè)線程分別運(yùn)行在兩個(gè)核上,大部分時(shí)間只有一個(gè)線程能拿到鎖,所以另一個(gè)線程就一直在它運(yùn)行的core上進(jìn)行忙等待,CPU占用率一直是100%;而mutex則不同,當(dāng)對(duì)鎖的請(qǐng)求失敗后上下文切換就會(huì)發(fā)生,這樣就能空出一個(gè)核來進(jìn)行別的運(yùn)算任務(wù)了。(其實(shí)這種上下文切換對(duì)已經(jīng)拿著鎖的那個(gè)線程性能也是有影響的,因?yàn)楫?dāng)該線程釋放該鎖時(shí)它需要通知操作系統(tǒng)去喚醒那些被阻塞的線程,這也是額外的開銷)

總結(jié)
(1)Mutex適合對(duì)鎖操作非常頻繁的場(chǎng)景,并且具有更好的適應(yīng)性。盡管相比spin lock它會(huì)花費(fèi)更多的開銷(主要是上下文切換),但是它能適合實(shí)際開發(fā)中復(fù)雜的應(yīng)用場(chǎng)景,在保證一定性能的前提下提供更大的靈活度。

(2)spin lock的lock/unlock性能更好(花費(fèi)更少的cpu指令),但是它只適應(yīng)用于臨界區(qū)運(yùn)行時(shí)間很短的場(chǎng)景。而在實(shí)際軟件開發(fā)中,除非程序員對(duì)自己的程序的鎖操作行為非常的了解,否則使用spin lock不是一個(gè)好主意(通常一個(gè)多線程程序中對(duì)鎖的操作有數(shù)以萬(wàn)次,如果失敗的鎖操作(contended lock requests)過多的話就會(huì)浪費(fèi)很多的時(shí)間進(jìn)行空等待)。

(3)更保險(xiǎn)的方法或許是先(保守的)使用 Mutex,然后如果對(duì)性能還有進(jìn)一步的需求,可以嘗試使用spin lock進(jìn)行調(diào)優(yōu)。畢竟我們的程序不像Linux kernel那樣對(duì)性能需求那么高(Linux Kernel最常用的鎖操作是spin lock和rw lock)。

2010年3月3日補(bǔ)記:這個(gè)觀點(diǎn)在Oracle的文檔中得到了支持:

During configuration, Berkeley DB selects a mutex implementation for the architecture. Berkeley DB normally prefers blocking-mutex implementations over non-blocking ones. For example, Berkeley DB will select POSIX pthread mutex interfaces rather than assembly-code test-and-set spin mutexes because pthread mutexes are usually more efficient and less likely to waste CPU cycles spinning without getting any work accomplished.

p.s.調(diào)用syscall(SYS_gettid)和syscall( __NR_gettid )都可以得到當(dāng)前線程的id:)

轉(zhuǎn)載請(qǐng)注明來自: [url]www.parallellabs.com[/url]
------------------------------------------------------------------------------

spinlock與linux內(nèi)核調(diào)度的關(guān)系


  作者:劉洪濤,華清遠(yuǎn)見嵌入式培訓(xùn)中心高級(jí)講師,ARM公司授權(quán)ATC講師。

廣告插播信息
維庫(kù)最新熱賣芯片:

  關(guān)于自旋鎖用法介紹的文章,已經(jīng)有很多,但有些細(xì)節(jié)的地方點(diǎn)的還不夠透。我這里就把我個(gè)人認(rèn)為大家容易有疑問的地方拿出來討論一下。

  一、自旋鎖(spinlock)簡(jiǎn)介

  自旋鎖在同一時(shí)刻只能被最多一個(gè)內(nèi)核任務(wù)持有,所以一個(gè)時(shí)刻只有一個(gè)線程允許存在于臨界區(qū)中。這點(diǎn)可以應(yīng)用在多處理機(jī)器、或運(yùn)行在單處理器上的搶占式內(nèi)核中需要的鎖定服務(wù)。

  二、信號(hào)量簡(jiǎn)介

  這里也介紹下信號(hào)量的概念,因?yàn)樗挠梅ê妥孕i有相似的地方。

  Linux中的信號(hào)量是一種睡眠鎖。如果有一個(gè)任務(wù)試圖獲得一個(gè)已被持有的信號(hào)量時(shí),信號(hào)量會(huì)將其推入等待隊(duì)列,然后讓其睡眠。這時(shí)處理器獲得自由去執(zhí)行其它代碼。當(dāng)持有信號(hào)量的進(jìn)程將信號(hào)量釋放后,在等待隊(duì)列中的一個(gè)任務(wù)將被喚醒,從而便可以獲得這個(gè)信號(hào)量。

  三、自旋鎖和信號(hào)量對(duì)比

  在很多地方自旋鎖和信號(hào)量可以選擇任何一個(gè)使用,但也有一些地方只能選擇某一種。下面對(duì)比一些兩者的用法。

  表1-1自旋鎖和信號(hào)量對(duì)比










  四、自旋鎖與linux內(nèi)核進(jìn)程調(diào)度關(guān)系

  我們討論下表1-1中的第3種情況(其它幾種情況比較好理解),如果臨界區(qū)可能包含引起睡眠的代碼則不能使用自旋鎖,否則可能引起死鎖。

  那么為什么信號(hào)量保護(hù)的代碼可以睡眠而自旋鎖就不能呢?

  先看下自旋鎖的實(shí)現(xiàn)方法吧,自旋鎖的基本形式如下:

  spin_lock(&mr_lock);

  //臨界區(qū)

  spin_unlock(&mr_lock);

  跟蹤一下spin_lock(&mr_lock)的實(shí)現(xiàn)

  #define spin_lock(lock) _spin_lock(lock)

  #define _spin_lock(lock) __LOCK(lock)

  #define __LOCK(lock) \

  do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

  注意到“preempt_disable()”,這個(gè)調(diào)用的功能是“關(guān)搶占”(在spin_unlock中會(huì)重新開啟搶占功能)。從中可以看出,使用自旋鎖保護(hù)的區(qū)域是工作在非搶占的狀態(tài);即使獲取不到鎖,在“自旋”狀態(tài)也是禁止搶占的。了解到這,我想咱們應(yīng)該能夠理解為何自旋鎖保護(hù)的代碼不能睡眠了。試想一下,如果在自旋鎖保護(hù)的代碼中間睡眠,此時(shí)發(fā)生進(jìn)程調(diào)度,則可能另外一個(gè)進(jìn)程會(huì)再次調(diào)用spinlock保護(hù)的這段代碼。而我們現(xiàn)在知道了即使在獲取不到鎖的“自旋”狀態(tài),也是禁止搶占的,而“自旋”又是動(dòng)態(tài)的,不會(huì)再睡眠了,也就是說在這個(gè)處理器上不會(huì)再有進(jìn)程調(diào)度發(fā)生了,那么死鎖自然就發(fā)生了。

  咱們可以總結(jié)下自旋鎖的特點(diǎn):

  ● 單處理器非搶占內(nèi)核下:自旋鎖會(huì)在編譯時(shí)被忽略;

  ● 單處理器搶占內(nèi)核下:自旋鎖僅僅當(dāng)作一個(gè)設(shè)置內(nèi)核搶占的開關(guān);

  ● 多處理器下:此時(shí)才能完全發(fā)揮出自旋鎖的作用,自旋鎖在內(nèi)核中主要用來防止多處理器中并發(fā)訪問臨界區(qū),防止內(nèi)核搶占造成的競(jìng)爭(zhēng)。

  五、linux搶占發(fā)生的時(shí)間

  最后在了解下linux搶占發(fā)生的時(shí)間,搶占分為用戶搶占和內(nèi)核搶占。

  用戶搶占在以下情況下產(chǎn)生:

  ● 從系統(tǒng)調(diào)用返回用戶空間

  ● 從中斷處理程序返回用戶空間

  內(nèi)核搶占會(huì)發(fā)生在:

  ● 當(dāng)從中斷處理程序返回內(nèi)核空間的時(shí)候,且當(dāng)時(shí)內(nèi)核具有可搶占性;

  ● 當(dāng)內(nèi)核代碼再一次具有可搶占性的時(shí)候。(如:spin_unlock時(shí))

  ● 如果內(nèi)核中的任務(wù)顯式的調(diào)用schedule()

  ● 如果內(nèi)核中的任務(wù)阻塞。

  基本的進(jìn)程調(diào)度就是發(fā)生在時(shí)鐘中斷后,并且發(fā)現(xiàn)進(jìn)程的時(shí)間片已經(jīng)使用完了,則發(fā)生進(jìn)程搶占。通常我們會(huì)利用中斷處理程序返回內(nèi)核空間的時(shí)候可以進(jìn)行內(nèi)核搶占這個(gè)特性來提高一些I/O操作的實(shí)時(shí)性,如:當(dāng)I/O事件發(fā)生的是時(shí)候,對(duì)應(yīng)的中斷處理程序被激活,當(dāng)它發(fā)現(xiàn)有進(jìn)程在等待這個(gè)I/O事件的時(shí)候,它會(huì)激活等待進(jìn)程,并且設(shè)置當(dāng)前正在執(zhí)行進(jìn)程的need_resched標(biāo)志,這樣在中斷處理程序返回的時(shí)候,調(diào)度程序被激活,原來在等待I/O事件的進(jìn)程(很可能)獲得執(zhí)行權(quán),從而保證了對(duì)I/O事件的相對(duì)快速響應(yīng)(毫秒級(jí))。可以看出,在I/O事件發(fā)生的時(shí)候,I/O事件的處理進(jìn)程會(huì)搶占當(dāng)前進(jìn)程,系統(tǒng)的響應(yīng)速度與調(diào)度時(shí)間片的長(zhǎng)度無關(guān)。

posted on 2010-09-21 15:15 Vincent 閱讀(3068) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 多線程


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(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| 老司机精品视频一区二区三区| 国产伊人精品| 欧美xxxx在线观看| 欧美国产一区在线| 亚洲视频在线观看视频| 亚洲一区二区精品| 国产主播一区| 亚洲大片免费看| 欧美三级电影大全| 久久精品天堂| 久久午夜av| 亚洲线精品一区二区三区八戒| 亚洲永久免费观看| 在线观看日韩精品| 亚洲精品影院在线观看| 国产精品免费一区二区三区在线观看 | 另类图片国产| 在线视频欧美日韩精品| 午夜精品国产更新| 亚洲激情六月丁香| 夜夜嗨一区二区| 一区二区视频免费完整版观看| 亚洲国产精品久久久久| 国产精品二区三区四区| 久久天堂成人| 国产精品久久久久久影院8一贰佰| 久久久综合网| 欧美三级视频在线播放| 另类人畜视频在线| 国产精品theporn| 欧美成人免费在线观看| 国产精品视频网站| 欧美福利小视频| 国产美女扒开尿口久久久| 亚洲经典视频在线观看| 国产视频不卡| 一本色道久久精品| 亚洲精品国产系列| 久久精品国产精品亚洲综合| 妖精成人www高清在线观看| 久久精品国产欧美激情| 亚洲欧洲av一区二区三区久久| 免费不卡中文字幕视频| 久久久亚洲综合| 国产精品美女久久久久久久 | 欧美一区二区三区免费视| 毛片一区二区| 媚黑女一区二区| 国一区二区在线观看| 一区二区毛片| 亚洲一区999| 欧美日韩国产影片| 91久久综合| 亚洲乱码国产乱码精品精可以看 | **网站欧美大片在线观看| 午夜老司机精品| 欧美一区二视频| 国产精品一区久久久| 一二美女精品欧洲| 亚洲视频在线观看| 欧美日韩一二三区| 一区二区国产日产| 在线一区二区三区四区五区| 欧美精品麻豆| 亚洲精品久久久久久一区二区| 亚洲国产精品久久人人爱蜜臀 | 久久精品亚洲热| 久久久久久久波多野高潮日日| 国产午夜精品一区理论片飘花| 亚洲欧美bt| 久久久视频精品| 影音先锋久久资源网| 久久久久九九九| 欧美11—12娇小xxxx| 亚洲精品国产精品国自产观看| 欧美精品福利| 夜夜精品视频一区二区| 亚洲女人天堂成人av在线| 国产日韩视频一区二区三区| 欧美一级在线亚洲天堂| 老鸭窝亚洲一区二区三区| 亚洲国产视频a| 欧美日韩成人一区二区| 亚洲午夜激情网站| 久久亚洲精品一区二区| 亚洲欧洲一区二区天堂久久| 欧美日韩国产成人精品| 亚洲午夜女主播在线直播| 久久深夜福利免费观看| 亚洲人体一区| 国产精品亚洲综合| 久久在线免费观看| 99精品99| 久久艳片www.17c.com| 亚洲精品免费在线播放| 国产精品你懂得| 美女视频网站黄色亚洲| 亚洲午夜91| 亚洲电影免费在线观看| 欧美一区中文字幕| 亚洲精品系列| 国内外成人免费视频| 欧美国产综合视频| 欧美伊人精品成人久久综合97| 亚洲国产成人高清精品| 久久精品电影| 亚洲素人在线| 亚洲国产精品嫩草影院| 国产伦精品一区二区三区四区免费 | 一本大道av伊人久久综合| 老鸭窝亚洲一区二区三区| 亚洲神马久久| 最近中文字幕日韩精品| 国产精品久久久久久影视| 牛夜精品久久久久久久99黑人| 亚洲欧美一区二区三区在线| 亚洲精品日韩欧美| 老司机一区二区| 久久精品99国产精品日本 | 国产欧美日韩在线观看| 欧美精品九九| 久久久在线视频| 亚洲欧美精品伊人久久| 欧美一区视频| 在线日本欧美| 免费成人av在线看| 久久av免费一区| 亚洲深夜福利| 曰韩精品一区二区| 国产丝袜一区二区| 欧美日韩精品综合在线| 麻豆精品网站| 欧美mv日韩mv国产网站| 久久亚洲国产成人| 久久精品主播| 久久久www成人免费精品| 午夜伦欧美伦电影理论片| 在线亚洲激情| 日韩小视频在线观看专区| 欧美国产日韩视频| 亚洲第一在线综合在线| 美女视频一区免费观看| 美女视频黄 久久| 欧美成人亚洲成人| 欧美国产日韩精品| 亚洲成人在线网| 欧美电影免费| 亚洲欧洲一区二区在线播放| 欧美高清成人| 亚洲国产精品成人| 欧美激情第五页| 亚洲精品视频一区| 在线一区免费观看| 亚洲新中文字幕| 久久黄色网页| 久久一区中文字幕| 欧美日韩p片| 国产精品一区在线观看你懂的| 国产精品国产三级国产aⅴ入口| 欧美日韩视频一区二区| 欧美日韩亚洲精品内裤| 国产精品久久久久影院亚瑟 | 久久综合999| 美国成人毛片| 欧美日韩三区| 国产女人精品视频| 国内精品国产成人| 日韩天堂在线观看| 在线综合亚洲| 久久久久久亚洲综合影院红桃 | 亚洲精品在线视频观看| 99re66热这里只有精品4| 99精品视频免费观看| 亚洲一区在线看| 久久亚洲高清| 一区二区福利| 欧美一级艳片视频免费观看| 男人的天堂亚洲在线| 欧美高清影院| 亚洲欧美国产制服动漫| 久久婷婷国产麻豆91天堂| 欧美日韩高清一区| 国产精品视频免费观看www| 亚洲国产一区二区三区a毛片 | 国产欧美丝祙| 亚洲国产一区二区a毛片| 午夜一区二区三视频在线观看 | 亚洲已满18点击进入久久| 久久精品国产欧美激情| 亚洲国产日韩欧美| 欧美一区二区三区免费观看| 欧美日韩免费观看中文| 娇妻被交换粗又大又硬视频欧美| 亚洲性夜色噜噜噜7777| 欧美成人免费全部| 久久国产精品久久久久久久久久 | 国产一区日韩欧美|