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

asm, c, c++ are my all
-- Core In Computer
posts - 139,  comments - 123,  trackbacks - 0
windows核心編程--線程的同步

線程的同步

由于同一進程的所有線程共享進程的虛擬地址空間,并且線程的中斷是匯編語言級的,所以可能會發生兩個線程同時訪問同一個對象(包括全局變量、共享資源、API函數和MFC對象等)的情況,這有可能導致程序錯誤。屬于不同進程的線程在同時訪問同一內存區域或共享資源時,也會存在同樣的問題。因此,在多線程應用程序中,常常需要采取一些措施來同步線程的執行。
需要同步的情況包括以下幾種:

在多個線程同時訪問同一對象時,可能產生錯誤。例如,如果當一個線程正在讀取一個至關重要的共享緩沖區時,另一個線程向該緩沖區寫入數據,那么程序的運行結果就可能出錯。程序應該盡量避免多個線程同時訪問同一個緩沖區或系統資源。

Windows 95環境下編寫多線程應用程序還需要考慮重入問題。Windows NT是真正的32位操作系統,它解決了系統重入問題。而Windows 95由于繼承了Windows 3.x的部分16位代碼,沒能夠解決重入問題。這意味著在Windows 95中兩個線程不能同時執行某個系統功能,否則有可能造成程序錯誤,甚至會造成系統崩潰。應用程序應該盡量避免發生兩個以上的線程同時調用同一個Windows API函數的情況。

由于大小和性能方面的原因,

MFC對象在對象級不是線程安全的,只有在類級才是。也就是說,兩個線程可以安全地使用兩個不同的CString對象,但同時使用同一個CString對象就可能產生問題。如果必須使用同一個對象,那么應該采取適當的同步措施。

多個線程之間需要協調運行。例如,如果第二個線程需要等待第一個線程完成到某一步時才能運行,那么該線程應該暫時掛起以減少對

CPU的占用時間,提高程序的執行效率。當第一個線程完成了相應的步驟后,應該發出某種信號來激活第二個線程。

關鍵節和互鎖變量訪問

關鍵節 (Critical Seciton)mutex 的功能類似,但它只能由同一進程中的線程使用。關鍵節可以防止共享資源被同時訪問。

進程負責為關鍵節分配內存空間,關鍵節實際上是一個CRITICAL_SECTION型的變量,它一次只能被一個線程擁有。在線程使用關鍵節之前,必須調用InitializeCriticalSection函數將其初始化。如果線程中有一段關鍵的代碼不希望被別的線程中斷,那么可以調用EnterCriticalSection函數來申請關鍵節的所有權,在運行完關鍵代碼后再用LeaveCriticalSection函數來釋放所有權。如果在調用EnterCriticalSection時關鍵節對象已被另一個線程擁有,那么該函數將無限期等待所有權。

利用互鎖變量可以建立簡單有效的同步機制。使用函數InterlockedIncrementInterlockedDecrement可以增加或減少多個線程共享的一個32位變量的值,并且可以檢查結果是否為0。線程不必擔心會被其它線程中斷而導致錯誤。如果變量位于共享內存中,那么不同進程中的線程也可以使用這種機制。

原子訪問


所謂原子訪問,是指線程在訪問資源時能夠確保所有其他線程都不在同一時間內訪問相同的資源。互鎖的函數家族:

				
				
				
LONG?InterlockedExchangeAdd(
???PLONG?plAddend,
???LONG?Increment);

這是個最簡單的函數了。只需調用這個函數,傳遞一個長變量地址,并指明將這個值遞增多少即可。但是這個函數能夠保證值的遞增以原子操作方式來完成。

						LONG InterlockedExchange(PLONG plTarget,
   LONG lValue);

PVOID InterlockedExchangePointer(PVOID* ppvTarget,
   PVOID pvValue);
				

I n t e r l o c k e d E x c h a n g e和I n t e r l o c k e d E x c h a n g e P o i n t e r能夠以原子操作方式用第二個參數中傳遞的值來取代第一個參數中傳遞的當前值。
------------------------------以上為用戶方式同步,以下為內核方式同步---------------------------------

等待函數

等待函數可使線程自愿進入等待狀態,直到一個特定的內核對象變為已通知狀態為止。 ???


DWORD?WaitForSingleObject(HANDLE?hObject,
???DWORD?dwMilliseconds);


函數Wa i t F o r M u l t i p l e O b j e c t s與Wa i t F o r S i n g l e O b j e c t函數很相似,區別在于它允許調用線程同時查看若干個內核對象的已通知狀態:

						DWORD WaitForMultipleObjects(DWORD dwCount,
   CONST HANDLE* phObjects, 
   BOOL fWaitAll, 
   DWORD dwMilliseconds);
				

同步對象

同步對象用來協調多線程的執行,它可以被多個線程共享。線程的等待函數用同步對象的句柄作為參數,同步對象應該是所有要使用的線程都能訪問到的。同步對象的狀態要么是有信號的,要么是無信號的。同步對象主要有三種:事件、 mutex 和信號燈。

事件對象 (Event) 是最簡單的同步對象,它包括有信號和無信號兩種狀態。在線程訪問某一資源之前,也許需要等待某一事件的發生,這時用事件對象最合適。例如,只有在通信端口緩沖區收到數據后,監視線程才被激活。

事件對象是用 CreateEvent 函數建立的。該函數可以指定事件對象的種類和事件的初始狀態。如果是手工重置事件,那么它總是保持有信號狀態,直到用 ResetEvent 函數重置成無信號的事件。如果是自動重置事件,那么它的狀態在單個等待線程釋放后會自動變為無信號的。用 SetEvent 可以把事件對象設置成有信號狀態。在建立事件時,可以為對象起個名字,這樣其它進程中的線程可以用 OpenEvent 函數打開指定名字的事件對象句柄。

mutex對象的狀態在它不被任何線程擁有時是有信號的,而當它被擁有時則是無信號的。mutex對象很適合用來協調多個線程對共享資源的互斥訪問(mutually exclusive)

線程用 CreateMutex 函數來建立 mutex 對象,在建立 mutex 時,可以為對象起個名字,這樣其它進程中的線程可以用 OpenMutex 函數打開指定名字的 mutex 對象句柄。在完成對共享資源的訪問后,線程可以調用 ReleaseMutex 來釋放 mutex ,以便讓別的線程能訪問共享資源。如果線程終止而不釋放 mutex ,則認為該 mutex 被廢棄。

信號燈對象維護一個從 0 開始的計數,在計數值大于 0 時對象是有信號的,而在計數值為 0 時則是無信號的。信號燈對象可用來限制對共享資源進行訪問的線程數量。線程用 CreateSemaphore 函數來建立信號燈對象,在調用該函數時,可以指定對象的初始計數和最大計數。在建立信號燈時也可以為對象起個名字,別的進程中的線程可以用 OpenSemaphore 函數打開指定名字的信號燈句柄。

一般把信號燈的初始計數設置成最大值。每次當信號燈有信號使等待函數返回時,信號燈計數就會減 1 ,而調用 ReleaseSemaphore 可以增加信號燈的計數。計數值越小就表明訪問共享資源的程序越多。

可用于同步的對象

對象

描述

變化通知

FindFirstChangeNotification 函數建立,當在指定目錄中發生指定類型的變化時對象變成有信號的。

控制臺輸入

在控制臺建立是被創建。它是用

CONIN$ 調用 CreateFile 函數返回的句柄,或是 GetStdHandle 函數的返回句柄。如果控制臺輸入緩沖區中有數據,那么對象是有信號的,如果緩沖區為空,則對象是無信號的。

進程

當調用

CreateProcess 建立進程時被創建。進程在運行時對象是無信號的,當進程終止時對象是有信號的。

線程

當調用

CreateprocessCreateThreadCreateRemoteThread 函數創建新線程時被創建。在線程運行是對象是無信號的,在線程終止時則是有信號的。
另外,有時可以用文件或通信設備作為同步對象使用。

事件內核對象

讓我們觀察一個簡單的例子,以便說明如何使用事件內核對象對線程進行同步。下面就是這個代碼:

										// Create a global handle to a manual-reset, nonsignaled event.
HANDLE g_hEvent;

int WINAPI WinMain(...) 
{
   //Create the manual-reset, nonsignaled event.
   g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

   //Spawn 3 new threads.
   HANDLE hThread[3];
   DWORD dwThreadID;
   hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &dwThreadID);
   hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &dwThreadID);
   hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &dwThreadID);

   OpenFileAndReadContentsIntoMemory(...);

   //Allow all 3 threads to access the memory.
   SetEvent(g_hEvent);
   ...
}

DWORD WINAPI WordCount(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}

DWORD WINAPI SpellCheck(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}

DWORD WINAPI GrammarCheck(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   return(0);
}
								
當這個進程啟動時,它創建一個人工重置的未通知狀態的事件,并且將句柄保存在一個全局變量中。這使得該進程中的其他線程能夠非常容易地訪問同一個事件對象。現在3個線程已經產生。這些線程要等待文件的內容讀入內存,然后每個線程都要訪問它的數據。一個線程進行單詞計數,另一個線程運行拼寫檢查器,第三個線程運行語法檢查器。這3個線程函數的代碼的開始部分都相同,每個函數都調用Wa i t F o r S i n g l e O b j e c t,這將使線程暫停運行,直到文件的內容由主線程讀入內存為止。

一旦主線程將數據準備好,它就調用S e t E v e n t,給事件發出通知信號。這時,系統就使所有這3個輔助線程進入可調度狀態,它們都獲得了C P U時間,并且可以訪問內存塊。注意,這3個線程都以只讀方式訪問內存。這就是所有3個線程能夠同時運行的唯一原因。還要注意,如何計算機上配有多個C P U,那么所有3個線程都能夠真正地同時運行,從而可以在很短的時間內完成大量的操作。

如果你使用自動重置的事件而不是人工重置的事件,那么應用程序的行為特性就有很大的差別。當主線程調用S e t E v e n t之后,系統只允許一個輔助線程變成可調度狀態。同樣,也無法保證系統將使哪個線程變為可調度狀態。其余兩個輔助線程將繼續等待。

已經變為可調度狀態的線程擁有對內存塊的獨占訪問權。讓我們重新編寫線程的函數,使得每個函數在返回前調用S e t E v e n t函數(就像Wi n M a i n函數所做的那樣)。這些線程函數現在變成下面的形式:

										DWORD WINAPI WordCount(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   SetEvent(g_hEvent);
   return(0);
}

DWORD WINAPI SpellCheck(PVOID pvParam) 
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   SetEvent(g_hEvent);
   return(0);
}

DWORD WINAPI GrammarCheck(PVOID pvParam)
{
   //Wait until the file's data is in memory.
   WaitForSingleObject(g_hEvent, INFINITE);

   //Access the memory block.
   ...
   SetEvent(g_hEvent);
   return(0);
}
								
當線程完成它對數據的專門傳遞時,它就調用S e t E v e n t函數,該函數允許系統使得兩個正在等待的線程中的一個成為可調度線程。同樣,我們不知道系統將選擇哪個線程作為可調度線程,但是該線程將進行它自己的對內存塊的專門傳遞。當該線程完成操作時,它也將調用S e t E v e n t函數,使第三個即最后一個線程進行它自己的對內存塊的傳遞。注意,當使用自動重置事件時,如果每個輔助線程均以讀/寫方式訪問內存塊,那么就不會產生任何問題,這些線程將不再被要求將數據視為只讀數據。


等待定時器內核對象

等待定時器是在某個時間或按規定的間隔時間發出自己的信號通知的內核對象。它們通常用來在某個時間執行某個操作。

若要創建等待定時器,只需要調用C r e a t e Wa i t a b l e Ti m e r函數:

						HANDLE CreateWaitableTimer(
   PSECURITY_ATTRIBUTES psa,
   BOOL fManualReset,
   PCTSTR pszName);
				
進程可以獲得它自己的與進程相關的現有等待定時器的句柄,方法是調用O p e n Wa i t a b l e Ti m e r函數:

						HANDLE OpenWaitableTimer(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);
				
當發出人工重置的定時器信號通知時,等待該定時器的所有線程均變為可調度線程。當發出自動重置的定時器信號通知時,只有一個等待的線程變為可調度線程。

等待定時器對象總是在未通知狀態中創建。必須調用S e t Wa i t a b l e Ti m e r函數來告訴定時器你想在何時讓它成為已通知狀態:

						BOOL SetWaitableTimer(
   HANDLE hTimer,
   const LARGE_INTEGER *pDueTime,
   LONG lPeriod,
   PTIMERAPCROUTINE pfnCompletionRoutine,
   PVOID pvArgToCompletionRoutine,
   BOOL fResume);
				
定時器函數外,最后還有一個C a n c e l Wa i t a b l e Ti m e r函數:

						BOOL CancelWaitableTimer(HANDLE hTimer);
				
這個簡單的函數用于取出定時器的句柄并將它撤消,這樣,除非接著調用S e t Wa i t a b l e Ti m e r函數以便重新設置定時器,否則定時器決不會進行報時。

信標內核對象

信標內核對象用于對資源進行計數。它們與所有內核對象一樣,包含一個使用數量,但是它們也包含另外兩個帶符號的3 2位值,一個是最大資源數量,一個是當前資源數量。最大資源數量用于標識信標能夠控制的資源的最大數量,而當前資源數量則用于標識當前可以使用的資源的數量。

信標的使用規則如下:

? 如果當前資源的數量大于0,則發出信標信號。

? 如果當前資源數量是0,則不發出信標信號。

? 系統決不允許當前資源的數量為負值。

? 當前資源數量決不能大于最大資源數量。

下面的函數用于創建信標內核對象:

								HANDLE CreateSemaphore(
   PSECURITY_ATTRIBUTE psa,
   LONG lInitialCount,
   LONG lMaximumCount,
   PCTSTR pszName);
						
通過調用O p e n S e m a p h o r e函數,另一個進程可以獲得它自己的進程與現有信標相關的句柄:

						HANDLE OpenSemaphore(
   DWORD fdwAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);
				

通過調用R e l e a s e S e m a p h o r e函數,線程就能夠對信標的當前資源數量進行遞增:

						BOOL ReleaseSemaphore(
   HANDLE hsem,
   LONG lReleaseCount,
   PLONG plPreviousCount);
				
互斥對象內核對象

互斥對象(m u t e x)內核對象能夠確保線程擁有對單個資源的互斥訪問權。
互斥對象有許多用途,屬于最常用的內核對象之一。通常來說,它們用于保護由多個線程訪問的內存塊。如果多個線程要同時訪問內存塊,內存塊中的數據就可能遭到破壞。互斥對象能夠保證訪問內存塊的任何線程擁有對該內存塊的獨占訪問權,這樣就能夠保證數據的完整性。

互斥對象的使用規則如下:

? 如果線程I D是0(這是個無效I D),互斥對象不被任何線程所擁有,并且發出該互斥對象的通知信號。

? 如果I D是個非0數字,那么一個線程就擁有互斥對象,并且不發出該互斥對象的通知信號。

? 與所有其他內核對象不同, 互斥對象在操作系統中擁有特殊的代碼,允許它們違反正常的規則(后面將要介紹這個異常情況)。

若要使用互斥對象,必須有一個進程首先調用C r e a t e M u t e x,以便創建互斥對象:

						HANDLE CreateMutex(
   PSECURITY_ATTRIBUTES psa,
   BOOL fInitialOwner,
   PCTSTR pszName);
				

通過調用O p e n M u t e x,另一個進程可以獲得它自己進程與現有互斥對象相關的句柄:

						HANDLE OpenMutex(
   DWORD fdwAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);
				

一旦線程成功地等待到一個互斥對象,該線程就知道它已經擁有對受保護資源的獨占訪問權。試圖訪問該資源的任何其他線程(通過等待相同的互斥對象)均被置于等待狀態中。當目前擁有對資源的訪問權的線程不再需要它的訪問權時,它必須調用R e l e a s e M u t e x函數來釋放該互斥對象:

						BOOL ReleaseMutex(HANDLE hMutex);
				

該函數將對象的遞歸計數器遞減1。

互斥對象與關鍵代碼段的比較

就等待線程的調度而言,互斥對象與關鍵代碼段之間有著相同的特性。但是它們在其他屬性方面卻各不相同。表9 - 1對它們進行了各方面的比較。

表9-1 互斥對象與關鍵代碼段的比較

特性 互斥對象 關鍵代碼段
運行速度
是否能夠跨進程邊界來使用
聲明 HANDLE hmtx; CRITICAL_SECTION cs;
初始化 h m t x = C r e a t e M u t e x(N U L L,FA L S E,N U L L); I n i t i a l i z e C r i t i c a l S e c t i o n ( & e s );
清除 C l o s e H a n d l e(h m t x); D e l e t e C r i t i c a l S e c t i o n(& c s);
無限等待 Wa i t F o r S i n g l e O b j e c t(h m t x , I N F I N I T E); E n t e r C r i t i c a l S e c t i o n(& c s);
0等待 Wa i t F o r S i n g l e O b j e c t Tr y(h m t x , 0); E n t e r C r i t i c a l S e c t i o n(& c s);
任意等待 Wa i t F o r S i n g l e O b j e c t(h m t x , d w M i l l i s e c o n d s); 不能
釋放 R e l e a s e M u t e x(h m t x); L e a v e C r i t i c a l S e c t i o n(& c s);
是否能夠等待其他內核對象 是(使用Wa i t F o r M u l t i p l e O b j e c t s或類似的函數)

線程同步對象速查表

內核對象與線程同步之間的相互關系
對象 何時處于未通知狀態 何時處于已通知狀態 成功等待的副作用
進程 當進程仍然活動時 當進程終止運行時(E x i t P r o c e s s,Te r m i n a t e P r o c e s s)
線程 當線程仍然活動時 當線程終止運行時(E x i t T h r e a d,Te r m i n a t e T h r e a d)
作業 當作業的時間尚未結束時 當作業的時間已經結束時
文件 當I / O請求正在處理時 當I / O請求處理完畢時
控制臺輸入 不存在任何輸入 當存在輸入時
文件修改通知 沒有任何文件被修改 當文件系統發現修改時 重置通知
自動重置事件 R e s e t E v e n t , P u l s e - E v e n t或等待成功 當調用S e t E v e n t / P u l s e E v e n t時 重置事件
人工重置事件 R e s e t E v e n t或P u l s e E v e n t 當調用S e t E v e n t / P u l s e E v e n t時
自動重置等待定時器 C a n c e l Wa i t a b l e Ti m e r或等待成功 當時間到時(S e t Wa i t a b l e Ti m e r) 重置定時器
人工重置等待定時器 C a n c e l Wa i t a b l e Ti m e r 當時間到時(S e t Wa i t a b l e Ti m e r)
信標 等待成功 當數量> 0時(R e l e a s e S e m a p h o r e) 數量遞減1
互斥對象 等待成功 當未被線程擁有時(R e l e a s e互斥對象) 將所有權賦予線程
關鍵代碼段(用戶方式) 等待成功((Tr y)E n t e r C r i t i c a l S e c t i o n) 當未被線程擁有時(L e a v e C r i t i c a l S e c t i o n) 將所有權賦予線程


其他的線程同步函數

1 異步設備I / O使得線程能夠啟動一個讀操作或寫操作,但是不必等待讀操作或寫操作完成。例如,如果線程需要將一個大文件裝入內存,那么該線程可以告訴系統將文件裝入內存。然后,當系統加載該文件時,該線程可以忙于執行其他任務,如創建窗口、對內部數據結構進行初始化等等。當初始化操作完成時,該線程可以終止自己的運行,等待系統通知它文件已經讀取。

2 線程也可以調用Wa i t F o r I n p u t I d l e來終止自己的運行:

												DWORD WaitForInputIdle(
   HANDLE hProcess,
   DWORD dwMilliseconds);
										

該函數將一直處于等待狀態,直到h P r o c e s s標識的進程在創建應用程序的第一個窗口的線程中已經沒有尚未處理的輸入為止。這個函數可以用于父進程。父進程產生子進程,以便執行某些操作。
3 線程可以調用M s g Wa i t F o r M u l t i p l e O b j e c t s或M s g Wa i t F o r M u l t i p l e O b j e c t s E x函數,讓線程等待它自己的消息:

												DWORD MsgWaitForMultipleObjects(
   DWORD dwCount,
   PHANDLE phObjects,
   BOOL fWaitAll,
   DWORD dwMilliseconds,
   DWORD dwWakeMask);

DWORD MsgWaitForMultipleObjectsEx(
   DWORD dwCount,
   PHANDLE phObjects,
   DWORD dwMilliseconds,
   DWORD dwWakeMask,
   DWORD dwFlags);
										

這些函數與Wa i t F o r M u l t i p l e O b j e c t s函數十分相似。差別在于它們允許線程在內核對象變成已通知狀態或窗口消息需要調度到調用線程創建的窗口中時被調度。

4 Wi n d o w s將非常出色的調試支持特性內置于操作系統之中。當調試程序啟動運行時,它將自己附加給一個被調試程序。該調試程序只需閑置著,等待操作系統將與被調試程序相關的調試事件通知它。調試程序通過調用Wa i t F o r D e b u g E v e n t函數來等待這些事件的發生:

												BOOL WaitForDebugEvent(
   PDEBUG_EVENT pde,
   DWORD dwMilliseconds);
										

當調試程序調用該函數時,調試程序的線程終止運行,系統將調試事件已經發生的情況通知調試程序,方法是允許調用的Wa i t F o r D e b u g E v e n t函數返回。

5 S i n g l e O b j e c t A n d Wa i t函數用于在單個原子方式的操作中發出關于內核對象的通知并等待另一個內核對象:

												DWORD SingleObjectAndWait(
   HANDLE hObjectToSignal,
   HANDLE hObjectToWaitOn,
   DWORD  dwMilliseconds,
   BOOL   fAlertable);
										
posted on 2006-10-13 19:47 Jerry Cat 閱讀(556) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理



<2025年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用鏈接

留言簿(7)

隨筆檔案

最新隨筆

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美一区二区三区日韩视频| 亚洲视频在线观看一区| 欧美不卡一区| 亚洲激情成人| 亚洲精选在线观看| 欧美激情 亚洲a∨综合| 欧美大片免费看| 亚洲综合久久久久| 亚洲理论在线观看| 国产精品欧美激情| 欧美诱惑福利视频| 亚洲人被黑人高潮完整版| 亚洲欧洲日本专区| 日韩一级在线| 亚洲国产欧美一区二区三区久久 | 欧美视频一区在线| 亚洲一区二区三区精品在线| 一区二区三区高清不卡| 欧美在线一区二区| 女女同性女同一区二区三区91| 欧美午夜一区| 亚洲无吗在线| 欧美777四色影视在线| 一区二区三区产品免费精品久久75 | 久久美女艺术照精彩视频福利播放| 黄色成人片子| 欧美色图天堂网| 亚洲一区二区日本| 亚洲一区精品电影| 亚洲欧洲日韩女同| 亚洲午夜国产成人av电影男同| 老司机精品视频一区二区三区| 中日韩高清电影网| 国产日韩一区二区三区在线播放 | 国产精品天天看| 激情欧美一区| 久久久国产一区二区三区| 一区二区三区视频观看| 亚洲大片精品永久免费| 日韩一级大片在线| 在线国产亚洲欧美| 国产精品亚发布| 麻豆国产va免费精品高清在线| 一区二区电影免费在线观看| 国产精品久久久久久久久免费| 欧美激情aⅴ一区二区三区| 欧美性视频网站| 欧美日韩精品免费看| 亚洲精品美女91| 麻豆乱码国产一区二区三区| 亚洲午夜日本在线观看| 99国产精品久久久久久久| 亚洲精品系列| 欧美伦理一区二区| 欧美人与性动交α欧美精品济南到 | 欧美一区三区三区高中清蜜桃| 日韩视频不卡中文| 牛牛国产精品| 欧美黑人一区二区三区| 欧美ed2k| 免费成人av在线| 欧美精品福利视频| 欧美午夜宅男影院| 一本色道久久综合亚洲二区三区| 亚洲欧洲在线免费| 亚洲尤物视频在线| 一区二区三区四区五区视频 | 亚洲欧美日韩另类| 亚洲精品一区二区在线观看| 欧美一级黄色网| 亚洲精品一二| 国产一区 二区 三区一级| 欧美午夜宅男影院在线观看| 亚洲少妇自拍| 美女国内精品自产拍在线播放| 91久久国产综合久久| 久久青草福利网站| 欧美69视频| 国产精品高潮久久| 小处雏高清一区二区三区 | 老**午夜毛片一区二区三区| 一本色道88久久加勒比精品| 久久激情婷婷| 欧美刺激午夜性久久久久久久| 午夜在线a亚洲v天堂网2018| 国产精品人人爽人人做我的可爱| 99re热这里只有精品免费视频| 亚洲欧美影音先锋| 亚洲国产精品www| 蜜臀av性久久久久蜜臀aⅴ| 欧美激情一区二区三区不卡| 国产精品视频免费观看www| 在线观看国产成人av片| 在线成人免费观看| 亚洲视频第一页| 亚洲自啪免费| 久久精品亚洲一区| 欧美激情网友自拍| 亚洲国产你懂的| 99在线|亚洲一区二区| 麻豆成人av| 一区一区视频| 亚洲日本黄色| 亚洲午夜一区| 久久免费视频这里只有精品| 一本久道久久综合中文字幕 | 野花国产精品入口| 亚洲精品自在在线观看| 久久精品72免费观看| 开心色5月久久精品| 亚洲一区二区三区在线看| 美女脱光内衣内裤视频久久影院| 欧美激情精品久久久六区热门| 国产欧美日韩精品丝袜高跟鞋 | 午夜精品福利一区二区蜜股av| 亚洲国产精品女人久久久| 国产日韩成人精品| 欧美日韩国产首页| 在线视频国内自拍亚洲视频| 一本色道久久综合亚洲精品高清| 亚洲欧美日韩综合| 欧美一区二区三区四区在线| 日韩视频在线观看一区二区| 亚洲视频在线观看一区| 亚洲区免费影片| 欧美成人黄色小视频| 91久久国产自产拍夜夜嗨| 国产伦精品一区二区三区四区免费 | 国产综合久久久久久鬼色| 一本色道久久加勒比精品| 鲁鲁狠狠狠7777一区二区| 亚洲欧洲一级| 久久久99免费视频| 国产欧美亚洲视频| 久久久亚洲午夜电影| 久久精品亚洲一区| 亚洲精品日韩精品| 99国产精品国产精品久久| 国产精品va在线播放| 亚洲一本大道在线| 国产精品乱码一区二区三区| 欧美在线视频全部完| 欧美在线观看视频一区二区三区| 久久精品91久久香蕉加勒比| 亚洲一区二区在线播放| 欧美在线观看一区| 日韩视频在线免费| 一区二区三区黄色| 国产亚洲精品资源在线26u| 欧美成人性网| 欧美国产日韩在线| 亚洲国产99| 亚洲欧美另类在线观看| 久久久噜噜噜久久中文字幕色伊伊| 亚洲精品一区二区三区99| 久久久精品日韩| 久久在精品线影院精品国产| 欧美va亚洲va日韩∨a综合色| 亚洲美女免费精品视频在线观看| 亚洲综合国产| 国产资源精品在线观看| 欧美有码在线视频| 另类酷文…触手系列精品集v1小说| 亚洲精品视频免费| 久久综合电影一区| 另类亚洲自拍| 欧美在线免费观看视频| 老司机精品导航| 欧美性开放视频| 美女国产精品| 一本一本久久| 久久久久久网站| 国内精品久久久久影院优| 午夜精品一区二区在线观看| 在线日韩av永久免费观看| 久久精品国产亚洲一区二区三区 | 国产亚洲欧美另类中文| 一本久久a久久精品亚洲| 国产精品网红福利| 99精品国产在热久久| 欧美午夜剧场| 欧美激情性爽国产精品17p| 欧美人交a欧美精品| 亚洲国产综合视频在线观看| 国产精品你懂的在线| 免费在线播放第一区高清av| 欧美日韩亚洲一区二区三区在线观看| 久久精品伊人| 欧美性做爰猛烈叫床潮| 美女视频一区免费观看| 国产精品高清一区二区三区| 久久电影一区| 亚洲黄色大片| 久久人体大胆视频| 欧美在线影院| 亚洲国产欧美一区二区三区同亚洲| 久久免费国产精品| 亚洲欧美成人一区二区在线电影 | 欧美一区二区福利在线| 欧美激情亚洲自拍|