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

巢穴

about:blank

【轉】線程同步-自旋鎖與Mutex/信號量的區別和聯系

POSIX threads(簡稱Pthreads)是在多核平臺上進行并行編程的一套常用的API。線程同步(Thread Synchronization)是并行編程中非常重要的通訊手段,其中最典型的應用就是用Pthreads提供的鎖機制(lock)來對多個線程之間共 享的臨界區(Critical Section)進行保護(另一種常用的同步機制是barrier)。

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

Pthreads提供的Mutex鎖操作相關的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鎖操作相關的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

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

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

那么在實際編程中mutex和spin lcok哪個的性能更好呢?我們知道spin lock在Linux內核中有非常廣泛的利用,那么這是不是說明spin lock的性能更好呢?下面讓我們來用實際的代碼測試一下(請確保你的系統中已經安裝了最近的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 }

該程序運行過程如下:主線程先初始化一個list結構,并根據LOOPS的值將對應數量的entry插入該list,之后創建兩個新線程,它們都執行consumer()這個任務。兩個被創建的新線程同時對這個list進行pop操作。主線程會計算從創建兩個新線程到兩個新線程結束之間所用的時間,輸出為下文中的”Result “。

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

從下面是測試結果:

查看源代碼打印幫助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的版本在該程序中表現出來的性能更好。另外值得注意的是sys時間,mutex版本花費了更多的系統調用時間,這就是因為mutex會在鎖沖突時調用system wait造成的。

但是,是不是說spin lock就一定更好了呢?讓我們再來看一個鎖沖突程度非常劇烈的實例程序:

查看源代碼打印幫助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 }

這個程序的特征就是臨界區非常大,這樣兩個線程的鎖競爭會非常的劇烈。當然這個是一個極端情況,實際應用程序中臨界區不會如此大,鎖競爭也不會如此激烈。測試結果顯示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

另外一個值得注意的細節是spin lock耗費了更多的user time。這就是因為兩個線程分別運行在兩個核上,大部分時間只有一個線程能拿到鎖,所以另一個線程就一直在它運行的core上進行忙等待,CPU占用率一直是100%;而mutex則不同,當對鎖的請求失敗后上下文切換就會發生,這樣就能空出一個核來進行別的運算任務了。(其實這種上下文切換對已經拿著鎖的那個線程性能也是有影響的,因為當該線程釋放該鎖時它需要通知操作系統去喚醒那些被阻塞的線程,這也是額外的開銷)

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

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

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

2010年3月3日補記:這個觀點在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.調用syscall(SYS_gettid)和syscall( __NR_gettid )都可以得到當前線程的id:)

轉載請注明來自: [url]www.parallellabs.com[/url]
------------------------------------------------------------------------------

spinlock與linux內核調度的關系


  作者:劉洪濤,華清遠見嵌入式培訓中心高級講師,ARM公司授權ATC講師。

廣告插播信息
維庫最新熱賣芯片:

  關于自旋鎖用法介紹的文章,已經有很多,但有些細節的地方點的還不夠透。我這里就把我個人認為大家容易有疑問的地方拿出來討論一下。

  一、自旋鎖(spinlock)簡介

  自旋鎖在同一時刻只能被最多一個內核任務持有,所以一個時刻只有一個線程允許存在于臨界區中。這點可以應用在多處理機器、或運行在單處理器上的搶占式內核中需要的鎖定服務。

  二、信號量簡介

  這里也介紹下信號量的概念,因為它的用法和自旋鎖有相似的地方。

  Linux中的信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然后讓其睡眠。這時處理器獲得自由去執行其它代碼。當持有信號量的進程將信號量釋放后,在等待隊列中的一個任務將被喚醒,從而便可以獲得這個信號量。

  三、自旋鎖和信號量對比

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

  表1-1自旋鎖和信號量對比










  四、自旋鎖與linux內核進程調度關系

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

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

  先看下自旋鎖的實現方法吧,自旋鎖的基本形式如下:

  spin_lock(&mr_lock);

  //臨界區

  spin_unlock(&mr_lock);

  跟蹤一下spin_lock(&mr_lock)的實現

  #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()”,這個調用的功能是“關搶占”(在spin_unlock中會重新開啟搶占功能)。從中可以看出,使用自旋鎖保護的區域是工作在非搶占的狀態;即使獲取不到鎖,在“自旋”狀態也是禁止搶占的。了解到這,我想咱們應該能夠理解為何自旋鎖保護的代碼不能睡眠了。試想一下,如果在自旋鎖保護的代碼中間睡眠,此時發生進程調度,則可能另外一個進程會再次調用spinlock保護的這段代碼。而我們現在知道了即使在獲取不到鎖的“自旋”狀態,也是禁止搶占的,而“自旋”又是動態的,不會再睡眠了,也就是說在這個處理器上不會再有進程調度發生了,那么死鎖自然就發生了。

  咱們可以總結下自旋鎖的特點:

  ● 單處理器非搶占內核下:自旋鎖會在編譯時被忽略;

  ● 單處理器搶占內核下:自旋鎖僅僅當作一個設置內核搶占的開關;

  ● 多處理器下:此時才能完全發揮出自旋鎖的作用,自旋鎖在內核中主要用來防止多處理器中并發訪問臨界區,防止內核搶占造成的競爭。

  五、linux搶占發生的時間

  最后在了解下linux搶占發生的時間,搶占分為用戶搶占和內核搶占。

  用戶搶占在以下情況下產生:

  ● 從系統調用返回用戶空間

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

  內核搶占會發生在:

  ● 當從中斷處理程序返回內核空間的時候,且當時內核具有可搶占性;

  ● 當內核代碼再一次具有可搶占性的時候。(如:spin_unlock時)

  ● 如果內核中的任務顯式的調用schedule()

  ● 如果內核中的任務阻塞。

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美午夜精品久久久久免费视| 一本久久综合亚洲鲁鲁| 日韩亚洲欧美中文三级| 99成人精品| 亚洲一区二区三区精品视频| 亚洲一区二区三区乱码aⅴ| 亚洲一区三区视频在线观看| 香蕉视频成人在线观看 | 欧美.com| 欧美成人午夜激情| 国产精品久久久久av免费| 国产精品美女一区二区| 韩国免费一区| 在线视频亚洲| 久久三级视频| 亚洲毛片在线看| 欧美资源在线观看| 欧美精品一区二区高清在线观看| 国产精品国产三级国产普通话99 | 制服丝袜亚洲播放| 欧美亚洲一区| 亚洲国产精品专区久久 | 欧美激情精品久久久久久大尺度| 欧美吻胸吃奶大尺度电影| 韩国av一区二区三区四区| 99视频+国产日韩欧美| 久久狠狠亚洲综合| 亚洲精品日韩久久| 久久中文字幕一区| 国产精品一区二区a| 亚洲精品韩国| 麻豆成人综合网| 亚洲影视在线播放| 欧美日韩精品久久| 91久久精品国产91久久| 欧美在线视频日韩| 中文日韩在线| 欧美日韩在线观看视频| 亚洲人成网站色ww在线| 噜噜噜久久亚洲精品国产品小说| 亚洲在线国产日韩欧美| 欧美日韩国产不卡| 日韩午夜av在线| 欧美激情精品久久久久久蜜臀| 欧美一区二区免费观在线| 欧美日韩精品免费观看视频完整| 亚洲激情另类| 欧美高清不卡| 麻豆av福利av久久av| 国产专区欧美精品| 久久九九国产| 欧美在线视频导航| 国内精品久久久久久久果冻传媒| 亚洲欧美日韩区 | 久久亚洲精品中文字幕冲田杏梨| 国产欧美日韩一区二区三区在线观看| 中文久久乱码一区二区| 日韩视频在线观看免费| 欧美日韩高清在线| 亚洲一区在线直播| 久久gogo国模啪啪人体图| 日韩性生活视频| 亚洲国产国产亚洲一二三| 快播亚洲色图| 亚洲日本一区二区| 亚洲国产成人在线视频| 欧美顶级大胆免费视频| 亚洲精品一区二区三区不| 亚洲人成人一区二区在线观看| 免费人成网站在线观看欧美高清| 亚洲国产精品久久久久| 亚洲国产成人在线| 欧美三级小说| 久久久久久久一区二区三区| 久久久久国产精品午夜一区| 亚洲第一二三四五区| 亚洲国产高清在线| 欧美亚男人的天堂| 久久先锋资源| 欧美精品三级在线观看| 中文在线资源观看网站视频免费不卡 | 夜色激情一区二区| 国产日韩欧美视频| 欧美激情综合色| 国产精品成人一区二区| 久久蜜桃资源一区二区老牛| 欧美99在线视频观看| 亚洲一区二区在线观看视频| 久久成人18免费网站| 夜夜躁日日躁狠狠久久88av| 午夜伦欧美伦电影理论片| 亚洲国产老妈| 亚洲网站在线| 亚洲人午夜精品| 午夜影院日韩| 中文日韩在线| 久久偷看各类wc女厕嘘嘘偷窃| 一区二区冒白浆视频| 久久精品亚洲一区二区| 亚洲无人区一区| 另类春色校园亚洲| 久久精品人人做人人综合| 男男成人高潮片免费网站| 欧美一级欧美一级在线播放| 欧美成人小视频| 久久躁狠狠躁夜夜爽| 国产精品久久久久久久久久ktv| 女同性一区二区三区人了人一| 国产精品久久久久91| 亚洲高清免费视频| 黑人极品videos精品欧美裸| 亚洲无线视频| 正在播放亚洲| 欧美成人国产| 欧美成人国产一区二区| 国内久久精品视频| 亚洲午夜一二三区视频| 亚洲美女在线国产| 91久久精品国产91久久性色| 性色av一区二区三区红粉影视| 一区二区三区高清| 欧美国产一区二区| 欧美大尺度在线| 一区久久精品| 久久久成人网| 浪潮色综合久久天堂| 国产亚洲一区二区精品| 午夜日韩激情| 久久久国产午夜精品| 国产欧美精品xxxx另类| 亚洲午夜性刺激影院| 亚洲一区二区三区精品在线| 欧美看片网站| 99天天综合性| 亚洲欧美不卡| 国产女精品视频网站免费 | 欧美二区在线| 亚洲国产精品久久91精品| 久久人人超碰| 欧美激情精品久久久| 亚洲乱码精品一二三四区日韩在线 | 久久久久久网| 黄网站免费久久| 久久久噜噜噜久久中文字免| 免费高清在线视频一区·| 亚洲电影免费在线观看| 欧美承认网站| 一区二区三区欧美在线观看| 午夜亚洲一区| 狠狠久久五月精品中文字幕| 老司机精品导航| 亚洲美女av在线播放| 香蕉久久国产| 激情欧美一区| 欧美人成在线| 亚洲欧美日韩第一区| 狼人天天伊人久久| 日韩亚洲欧美在线观看| 国产模特精品视频久久久久| 久久激情五月婷婷| 亚洲国产清纯| 亚洲欧美一区二区三区极速播放| 国产深夜精品福利| 欧美电影免费观看高清完整版| 99精品视频免费| 久久久久久久久久久一区| 亚洲卡通欧美制服中文| 国产精品一区二区欧美| 狂野欧美激情性xxxx| 宅男噜噜噜66一区二区66| 免费不卡视频| 亚洲欧美日韩精品综合在线观看| 精品69视频一区二区三区| 欧美日韩一区二| 久久综合九色综合网站| 亚洲一区二区久久| 亚洲缚视频在线观看| 欧美在线观看天堂一区二区三区| 91久久线看在观草草青青| 国产日产精品一区二区三区四区的观看方式 | 亚洲欧美在线免费| 亚洲国产精品久久久久婷婷884| 亚洲欧美中文日韩在线| 亚洲高清不卡在线观看| 国产精品女主播在线观看| 欧美成人免费一级人片100| 欧美亚洲一级片| 国产精品99久久久久久久女警| 欧美电影电视剧在线观看| 欧美在线不卡| 亚洲中字黄色| 夜夜爽av福利精品导航| 亚洲国产小视频| 黄色国产精品| 国产日韩欧美精品在线| 国产精品女人网站| 国产精品成人观看视频国产奇米| 欧美高潮视频| 欧美成人精品一区二区| 麻豆久久久9性大片|