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

那誰(shuí)的技術(shù)博客

感興趣領(lǐng)域:高性能服務(wù)器編程,存儲(chǔ),算法,Linux內(nèi)核
隨筆 - 210, 文章 - 0, 評(píng)論 - 1183, 引用 - 0
數(shù)據(jù)加載中……

Linux下面的線程鎖,條件變量以及信號(hào)量的使用

一) 線程鎖
1) 只能用于"鎖"住臨界代碼區(qū)域
2) 一個(gè)線程加的鎖必須由該線程解鎖.

鎖幾乎是我們學(xué)習(xí)同步時(shí)最開始接觸到的一個(gè)策略,也是最簡(jiǎn)單, 最直白的策略.

二) 條件變量,與鎖不同, 條件變量用于等待某個(gè)條件被觸發(fā)
1) 大體使用的偽碼:

// 線程一代碼
pthread_mutex_lock(&mutex);
// 設(shè)置條件為true
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

// 線程二代碼
pthread_mutex_lock(&mutex);
while (條件為false)
    pthread_cond_wait(&cond, &mutex);
修改該條件
pthread_mutex_unlock(&mutex);

需要注意幾點(diǎn):
1) 第二段代碼之所以在pthread_cond_wait外面包含一個(gè)while循環(huán)不停測(cè)試條件是否成立的原因是, 在pthread_cond_wait被喚醒的時(shí)候可能該條件已經(jīng)不成立.UNPV2對(duì)這個(gè)的描述是:"Notice that when pthread_cond_wait returns, we always test the condition again, because spurious wakeups can occur: a wakeup when the desired condition is still not true.".

2) pthread_cond_wait調(diào)用必須和某一個(gè)mutex一起調(diào)用, 這個(gè)mutex是在外部進(jìn)行加鎖的mutex, 在調(diào)用pthread_cond_wait時(shí), 內(nèi)部的實(shí)現(xiàn)將首先將這個(gè)mutex解鎖, 然后等待條件變量被喚醒, 如果沒有被喚醒, 該線程將一直休眠, 也就是說(shuō), 該線程將一直阻塞在這個(gè)pthread_cond_wait調(diào)用中, 而當(dāng)此線程被喚醒時(shí), 將自動(dòng)將這個(gè)mutex加鎖.
man文檔中對(duì)這部分的說(shuō)明是:
pthread_cond_wait atomically unlocks the mutex (as per pthread_unlock_mutex) and waits for the condition variable cond to  be  signaled.  The thread execution is suspended and does not consume any CPU time until the condition variable is
signaled. The mutex must be locked by the calling thread on entrance to pthread_cond_wait.  Before  returning  to  the calling thread, pthread_cond_wait re-acquires mutex (as per pthread_lock_mutex).
也就是說(shuō)pthread_cond_wait實(shí)際上可以看作是以下幾個(gè)動(dòng)作的合體:
解鎖線程鎖
等待條件為true
加鎖線程鎖.

這里是使用條件變量的經(jīng)典例子:
http://www.shnenglu.com/CppExplore/archive/2008/03/20/44949.html
之所以使用兩個(gè)條件變量, 是因?yàn)橛袃煞N情況需要進(jìn)行保護(hù),使用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列,因此一個(gè)條件是在getq函數(shù)中判斷讀寫指針相同且可讀數(shù)據(jù)計(jì)數(shù)為0,此時(shí)隊(duì)列為空沒有數(shù)據(jù)可讀,因此獲取新數(shù)據(jù)的條件變量就一直等待,另一個(gè)條件是讀寫指針相同且可讀數(shù)據(jù)計(jì)數(shù)大于0,此時(shí)隊(duì)列滿了不能再添加數(shù)據(jù), 因此添加新數(shù)據(jù)的條件變量就一直等待,而nEmptyThreadNum和nFullThreadNum則是計(jì)數(shù), 只有這個(gè)計(jì)數(shù)大于0時(shí)才會(huì)喚醒相應(yīng)的條件變量,這樣可以減少調(diào)用pthread_cond_signal的次數(shù).
為了在下面的敘述方便, 我將這段代碼整理在下面, 是一個(gè)可以編譯運(yùn)行的代碼,但是注意需要在編譯時(shí)加上-pthread鏈接線程庫(kù):
#include <pthread.h>
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>

class CThreadQueue
{
public:
    CThreadQueue(
int queueSize=1024):
        sizeQueue(queueSize),lput(
0),lget(0),nFullThread(0),nEmptyThread(0),nData(0)
    {
        pthread_mutex_init(
&mux,0);
        pthread_cond_init(
&condGet,0);
        pthread_cond_init(
&condPut,0);
        buffer
=new void *[sizeQueue];
    }
    
virtual ~CThreadQueue()
    {
        delete[] buffer;
    }
    
void * getq()
    {
        
void *data;
        pthread_mutex_lock(
&mux);
        /*
         此 處循環(huán)判斷的原因如下:假設(shè)2個(gè)線程在getq阻塞,然后兩者都被激活,而其中一個(gè)線程運(yùn)行比較塊,快速消耗了2個(gè)數(shù)據(jù),另一個(gè)線程醒來(lái)的時(shí)候已經(jīng)沒有新 數(shù)據(jù)可以消耗了。另一點(diǎn),man pthread_cond_wait可以看到,該函數(shù)可以被信號(hào)中斷返回,此時(shí)返回EINTR。為避免以上任何一點(diǎn),都必須醒來(lái)后再次判斷睡眠條件。更 正:pthread_cond_wait是信號(hào)安全的系統(tǒng)調(diào)用,不會(huì)被信號(hào)中斷。
        */
        while(lget==lput&&nData==0)
        {
            nEmptyThread
++;
            pthread_cond_wait(
&condGet,&mux);
            nEmptyThread
--;     
        }

        data
=buffer[lget++];
        nData
--;
        
if(lget==sizeQueue)
        {
            lget
=0;
        }
        
if(nFullThread) //必要時(shí)才進(jìn)行signal操作,勿總是signal
        {
            pthread_cond_signal(
&condPut);    
        }
        pthread_mutex_unlock(
&mux);
        
return data;
    }
    
void putq(void *data)
    {
        pthread_mutex_lock(
&mux);
        
while(lput==lget&&nData)
        { 
            nFullThread
++;
            pthread_cond_wait(
&condPut,&mux);
            nFullThread
--;
        }
        buffer[lput
++]=data;
        nData
++;
        
if(lput==sizeQueue)
        {
            lput
=0;
        }
        
if(nEmptyThread) //必要時(shí)才進(jìn)行signal操作,勿總是signal
        {
            pthread_cond_signal(
&condGet);
        }
        pthread_mutex_unlock(
&mux);
    }
private:
    pthread_mutex_t mux;
    pthread_cond_t condGet;
    pthread_cond_t condPut;

    
void * * buffer;    //循環(huán)消息隊(duì)列
    int sizeQueue;        //隊(duì)列大小
    int lput;        //location put  放數(shù)據(jù)的指針偏移
    int lget;        //location get  取數(shù)據(jù)的指針偏移
    int nFullThread;    //隊(duì)列滿,阻塞在putq處的線程數(shù)
    int nEmptyThread;    //隊(duì)列空,阻塞在getq處的線程數(shù)
    int nData;        //隊(duì)列中的消息個(gè)數(shù),主要用來(lái)判斷隊(duì)列空還是滿
};

CThreadQueue queue;
//使用的時(shí)候給出稍大的CThreadQueue初始化參數(shù),可以減少進(jìn)入內(nèi)核態(tài)的操作。

void * produce(void * arg)
{
    
int i=0;
    pthread_detach(pthread_self());
    
while(i++<100)
    {
        queue.putq((
void *)i);
    }
}

void *consume(void *arg)
{
    
int data;
    
while(1)
    {
        data
=(int)(queue.getq());
        printf(
"data=%d\n",data);
    }
}

int main()
{    
    pthread_t pid;
    
int i=0;

    
while(i++<3)
        pthread_create(
&pid,0,produce,0);
    i
=0;
    
while(i++<3)
        pthread_create(
&pid,0,consume,0);
    sleep(
5);

    
return 0;
}


三) 信號(hào)量
信號(hào)量既可以作為二值計(jì)數(shù)器(即0,1),也可以作為資源計(jì)數(shù)器.
主要是兩個(gè)函數(shù):
sem_wait()  decrements  (locks)  the semaphore pointed to by sem.  If the semaphore's value is greater than zero, then
the decrement proceeds, and the function returns, immediately.  If the semaphore currently has the  value  zero,  then
the  call  blocks  until  either  it  becomes possible to perform the decrement (i.e., the semaphore value rises above
zero), or a signal handler interrupts the call.

sem_post()  increments  (unlocks)  the  semaphore  pointed  to  by sem.  If the semaphore's value consequently becomes
greater than zero, then another process or thread blocked in a sem_wait(3) call will be woken up and proceed  to  lock
the semaphore.

而函數(shù)int sem_getvalue(sem_t *sem, int *sval);則用于獲取信號(hào)量當(dāng)前的計(jì)數(shù).

可以用信號(hào)量模擬鎖和條件變量:
1) 鎖,在同一個(gè)線程內(nèi)同時(shí)對(duì)某個(gè)信號(hào)量先調(diào)用sem_wait再調(diào)用sem_post, 兩個(gè)函數(shù)調(diào)用其中的區(qū)域就是所要保護(hù)的臨界區(qū)代碼了,這個(gè)時(shí)候其實(shí)信號(hào)量是作為二值計(jì)數(shù)器來(lái)使用的.不過(guò)在此之前要初始化該信號(hào)量計(jì)數(shù)為1,見下面例子中的代碼.
2) 條件變量,在某個(gè)線程中調(diào)用sem_wait, 而在另一個(gè)線程中調(diào)用sem_post.

我們將上面例子中的線程鎖和條件變量都改成用信號(hào)量實(shí)現(xiàn)以說(shuō)明信號(hào)量如何模擬兩者:
#include <pthread.h>
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<fcntl.h>
#include 
<sys/stat.h>
#include 
<semaphore.h>
#include 
<errno.h>
#include 
<string.h>

class CThreadQueue
{
public:
    CThreadQueue(
int queueSize=1024):
        sizeQueue(queueSize),lput(
0),lget(0),nFullThread(0),nEmptyThread(0),nData(0)
    {
        
//pthread_mutex_init(&mux,0);
        mux = sem_open("mutex", O_RDWR | O_CREAT);
        
get = sem_open("get", O_RDWR | O_CREAT);
        put 
= sem_open("put", O_RDWR | O_CREAT);
    
        sem_init(mux, 
01);

        buffer
=new void *[sizeQueue];
    }
    
virtual ~CThreadQueue()
    {
        delete[] buffer;
        sem_unlink(
"mutex");
        sem_unlink(
"get");
        sem_unlink(
"put");
    }
    
void * getq()
    {
        
void *data;

        
//pthread_mutex_lock(&mux);
        sem_wait(mux);

        
while(lget==lput&&nData==0)
        {
            nEmptyThread
++;
            
//pthread_cond_wait(&condGet,&mux);
            sem_wait(get);
            nEmptyThread
--;     
        }

        data
=buffer[lget++];
        nData
--;
        
if(lget==sizeQueue)
        {
            lget
=0;
        }
        
if(nFullThread) //必要時(shí)才進(jìn)行signal操作,勿總是signal
        {
            
//pthread_cond_signal(&condPut);    
            sem_post(put);
        }

        
//pthread_mutex_unlock(&mux);
        sem_post(mux);

        
return data;
    }
    
void putq(void *data)
    {
        
//pthread_mutex_lock(&mux);
        sem_wait(mux);

        
while(lput==lget&&nData)
        { 
            nFullThread
++;
            
//pthread_cond_wait(&condPut,&mux);
            sem_wait(put);
            nFullThread
--;
        }
        buffer[lput
++]=data;
        nData
++;
        
if(lput==sizeQueue)
        {
            lput
=0;
        }
        
if(nEmptyThread)
        {
            
//pthread_cond_signal(&condGet);
            sem_post(get);
        }

        
//pthread_mutex_unlock(&mux);
        sem_post(mux);
    }
private:
    
//pthread_mutex_t mux;
    sem_t* mux;
    
//pthread_cond_t condGet;
    
//pthread_cond_t condPut;
    sem_t* get;
    sem_t
* put;

    
void * * buffer;    //循環(huán)消息隊(duì)列
    int sizeQueue;        //隊(duì)列大小
    int lput;        //location put  放數(shù)據(jù)的指針偏移
    int lget;        //location get  取數(shù)據(jù)的指針偏移
    int nFullThread;    //隊(duì)列滿,阻塞在putq處的線程數(shù)
    int nEmptyThread;    //隊(duì)列空,阻塞在getq處的線程數(shù)
    int nData;        //隊(duì)列中的消息個(gè)數(shù),主要用來(lái)判斷隊(duì)列空還是滿
};

CThreadQueue queue;
//使用的時(shí)候給出稍大的CThreadQueue初始化參數(shù),可以減少進(jìn)入內(nèi)核態(tài)的操作。

void * produce(void * arg)
{
    
int i=0;
    pthread_detach(pthread_self());
    
while(i++<100)
    {
        queue.putq((
void *)i);
    }
}

void *consume(void *arg)
{
    
int data;
    
while(1)
    {
        data
=(int)(queue.getq());
        printf(
"data=%d\n",data);
    }
}

int main()
{    
    pthread_t pid;
    
int i=0;

    
while(i++<3)
        pthread_create(
&pid,0,produce,0);
    i
=0;
    
while(i++<3)
        pthread_create(
&pid,0,consume,0);
    sleep(
5);

    
return 0;
}


不過(guò), 信號(hào)量除了可以作為二值計(jì)數(shù)器用于模擬線程鎖和條件變量之外, 還有比它們更加強(qiáng)大的功能, 信號(hào)量可以用做資源計(jì)數(shù)器, 也就是說(shuō)初始化信號(hào)量的值為某個(gè)資源當(dāng)前可用的數(shù)量, 使用了一個(gè)之后遞減, 歸還了一個(gè)之后遞增, 將前面的例子用資源計(jì)數(shù)器的形式再次改寫如下,注意在初始化的時(shí)候要將資源計(jì)數(shù)進(jìn)行初始化, 在下面代碼中的構(gòu)造函數(shù)中將put初始化為隊(duì)列的最大數(shù)量, 而get為0:
#include <pthread.h>
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<fcntl.h>
#include 
<sys/stat.h>
#include 
<semaphore.h>

class CThreadQueue
{
public:
    CThreadQueue(
int queueSize=1024):
        sizeQueue(queueSize),lput(
0),lget(0)
    {
        pthread_mutex_init(
&mux,0);
        
get = sem_open("get", O_RDWR | O_CREAT);
        put 
= sem_open("put", O_RDWR | O_CREAT);

        sem_init(
get00);
        sem_init(put, 
0, sizeQueue);

        buffer
=new void *[sizeQueue];
    }
    
virtual ~CThreadQueue()
    {
        sem_unlink(
"get");
        sem_unlink(
"put");
        delete[] buffer;
    }
    
void * getq()
    {
        sem_wait(
get);

        
void *data;

        pthread_mutex_lock(
&mux);

        
/*
        while(lget==lput&&nData==0)
        {
            nEmptyThread++;
            //pthread_cond_wait(&condGet,&mux);
            nEmptyThread--;     
        }
        
*/

        data
=buffer[lget++];
        
//nData--;
        if(lget==sizeQueue)
        {
            lget
=0;
        }
        
/*
        if(nFullThread) //必要時(shí)才進(jìn)行signal操作,勿總是signal
        {
            //pthread_cond_signal(&condPut);    
            sem_post(put);
        }
        
*/
        pthread_mutex_unlock(
&mux);

        sem_post(put);

        
return data;
    }
    
void putq(void *data)
    {
        sem_wait(put);

        pthread_mutex_lock(
&mux);

        
/*
        while(lput==lget&&nData)
        { 
            nFullThread++;
            //pthread_cond_wait(&condPut,&mux);
            sem_wait(put);
            nFullThread--;
        }
        
*/

        buffer[lput
++]=data;
        
//nData++;
        if(lput==sizeQueue)
        {
            lput
=0;
        }
        
/*
        if(nEmptyThread)
        {
            //pthread_cond_signal(&condGet);
            sem_post(get);
        }
        
*/

        pthread_mutex_unlock(
&mux);

        sem_post(
get);
    }
private:
    pthread_mutex_t mux;
    
//pthread_cond_t condGet;
    
//pthread_cond_t condPut;
    sem_t* get;
    sem_t
* put;

    
void * * buffer;    //循環(huán)消息隊(duì)列
    int sizeQueue;        //隊(duì)列大小
    int lput;        //location put  放數(shù)據(jù)的指針偏移
    int lget;        //location get  取數(shù)據(jù)的指針偏移
};

CThreadQueue queue;
//使用的時(shí)候給出稍大的CThreadQueue初始化參數(shù),可以減少進(jìn)入內(nèi)核態(tài)的操作。

void * produce(void * arg)
{
    
int i=0;
    pthread_detach(pthread_self());
    
while(i++<100)
    {
        queue.putq((
void *)i);
    }
}

void *consume(void *arg)
{
    
int data;
    
while(1)
    {
        data
=(int)(queue.getq());
        printf(
"data=%d\n",data);
    }
}

int main()
{    
    pthread_t pid;
    
int i=0;

    
while(i++<3)
        pthread_create(
&pid,0,produce,0);
    i
=0;
    
while(i++<3)
        pthread_create(
&pid,0,consume,0);
    sleep(
5);

    
return 0;
}

可以看見,采用信號(hào)量作為資源計(jì)數(shù)之后, 代碼變得"很直白",原來(lái)的一些保存隊(duì)列狀態(tài)的變量都不再需要了.

信號(hào)量與線程鎖,條件變量相比還有以下幾點(diǎn)不同:
1)鎖必須是同一個(gè)線程獲取以及釋放, 否則會(huì)死鎖.而條件變量和信號(hào)量則不必.
2)信號(hào)的遞增與減少會(huì)被系統(tǒng)自動(dòng)記住, 系統(tǒng)內(nèi)部有一個(gè)計(jì)數(shù)器實(shí)現(xiàn)信號(hào)量,不必?fù)?dān)心會(huì)丟失, 而喚醒一個(gè)條件變量時(shí),如果沒有相應(yīng)的線程在等待該條件變量, 這次喚醒將被丟失.

posted on 2009-01-15 10:23 那誰(shuí) 閱讀(15704) 評(píng)論(3)  編輯 收藏 引用 所屬分類: Linux/Unix

評(píng)論

# re: Linux下面的線程鎖,條件變量以及信號(hào)量的使用  回復(fù)  更多評(píng)論   

第二段程序模擬線程鎖中有bug,sem_wait(get)跟sem_wait(put)前后需要加上解鎖加鎖動(dòng)作。

produce 和 consume 的設(shè)計(jì),隊(duì)列大小為1024,測(cè)試數(shù)據(jù)3x100太小。while循環(huán)中最好加上usleep讓線程休息一會(huì)兒,否則consume極可能需要在produce線程跑完了之后才獲得鎖,對(duì)測(cè)試程序不利。
2009-01-27 08:57 | Mensch88

# re: Linux下面的線程鎖,條件變量以及信號(hào)量的使用  回復(fù)  更多評(píng)論   

關(guān)于最后一段對(duì)用信號(hào)量實(shí)現(xiàn)通知/等待機(jī)制和用條件變量來(lái)實(shí)現(xiàn)相同機(jī)制的比較,所說(shuō)的兩點(diǎn)都對(duì)信號(hào)量有利,那條件變量多余了嗎?
2009-02-11 11:39 | yqiang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久躁日日躁aaaaxxxx| 一本久道久久综合狠狠爱| 午夜精品福利视频| 一本色道久久综合狠狠躁篇的优点 | 亚洲国产精品一区二区第四页av| 久久综合国产精品| 欧美成人精品h版在线观看| 日韩视频国产视频| 一区二区三区www| 国产精品网站视频| 免费亚洲网站| 欧美日韩黄视频| 久久精品国产视频| 欧美成熟视频| 午夜精品久久久久久久久久久久| 欧美在线亚洲| 亚洲最快最全在线视频| 午夜精品久久久久久久男人的天堂 | 久久精品久久综合| 欧美成人午夜视频| 亚洲欧美日韩国产中文| 久久精品亚洲热| 一区二区不卡在线视频 午夜欧美不卡在 | 久久综合中文字幕| 欧美精品久久99久久在免费线| 亚洲欧美精品伊人久久| 久久久久久久国产| 亚洲一区二区视频在线观看| 久久精品在线观看| 国产精品99久久久久久白浆小说 | 久久一区二区三区超碰国产精品| 99精品热6080yy久久| 欧美一级视频精品观看| 在线综合亚洲欧美在线视频| 久久久久一区二区三区四区| 亚洲丝袜av一区| 欧美h视频在线| 久久久综合精品| 国产精品成人aaaaa网站 | 性欧美长视频| 欧美区国产区| 欧美国产高潮xxxx1819| 国产精品一二| 一区二区三区回区在观看免费视频| 在线电影一区| 欧美影院在线播放| 翔田千里一区二区| 欧美午夜免费影院| 亚洲美女av黄| 亚洲精品资源美女情侣酒店| 久久人人97超碰精品888| 欧美资源在线观看| 国产精品色一区二区三区| 日韩亚洲精品视频| 一区二区免费看| 欧美精品国产精品日韩精品| 亚洲国产精品女人久久久| 国产日韩综合一区二区性色av| 亚洲免费观看在线视频| 夜夜夜久久久| 欧美日韩另类综合| 日韩亚洲国产精品| 亚洲午夜精品久久| 欧美性猛交视频| 亚洲图片在线观看| 性欧美1819性猛交| 国产乱码精品一区二区三区忘忧草| 中文av一区二区| 香蕉视频成人在线观看| 国产欧美日韩麻豆91| 久久爱www久久做| 蜜臀av国产精品久久久久| 亚洲国产经典视频| 欧美精品一区三区在线观看| 亚洲精品裸体| 亚洲女优在线| 国产一区999| 久久综合网络一区二区| 91久久精品日日躁夜夜躁欧美| 亚洲精品国产精品久久清纯直播| 欧美国产欧美亚州国产日韩mv天天看完整| 欧美国产一区二区在线观看| 亚洲精品国久久99热| 欧美日韩免费区域视频在线观看| 亚洲国产婷婷| 91久久精品www人人做人人爽| 亚洲精品国产精品国产自| 欧美啪啪成人vr| 亚洲免费中文字幕| 久久综合九色欧美综合狠狠| 91久久精品久久国产性色也91| 欧美啪啪一区| 久久爱91午夜羞羞| 亚洲精品在线三区| 久久成人资源| 亚洲免费观看在线观看| 国产欧美精品在线观看| 美女视频黄免费的久久| 亚洲无限乱码一二三四麻| 久久综合九色综合久99| 亚洲神马久久| 国语自产在线不卡| 欧美日韩在线另类| 久久免费99精品久久久久久| 亚洲精品在线免费| 美女诱惑黄网站一区| 亚洲欧美在线磁力| 亚洲精品自在久久| 一区在线免费| 国产精品视频一区二区高潮| 欧美成人午夜影院| 久久久www成人免费无遮挡大片 | 香蕉国产精品偷在线观看不卡| 免费看黄裸体一级大秀欧美| 午夜激情久久久| 亚洲美女精品成人在线视频| 国产资源精品在线观看| 欧美天堂亚洲电影院在线播放| 老牛嫩草一区二区三区日本| 先锋资源久久| 亚洲一区二区三区欧美| 亚洲精品久久嫩草网站秘色| 毛片基地黄久久久久久天堂| 欧美一区二区在线播放| 中文国产一区| 在线亚洲观看| 99av国产精品欲麻豆| 亚洲福利视频网| 黑丝一区二区三区| 国产亚洲精品一区二区| 国产精品日本一区二区| 欧美吻胸吃奶大尺度电影| 欧美日韩精品综合| 欧美精品激情| 欧美理论在线| 欧美日韩免费在线| 欧美日韩国产一区| 欧美久久久久久| 欧美日韩精品一区二区在线播放| 欧美激情一区二区三区蜜桃视频 | 一区二区亚洲欧洲国产日韩| 国产丝袜美腿一区二区三区| 国产欧美一区二区三区视频| 国产精品久久毛片a| 国产精品午夜av在线| 国产精品一区二区你懂的| 国产裸体写真av一区二区| 国产人久久人人人人爽| 国产亚洲精品久久久久久| 激情欧美一区| 亚洲精品视频啊美女在线直播| 亚洲日本激情| 亚洲网站在线播放| 性欧美xxxx大乳国产app| 国产精品久久一区主播| 久久精品盗摄| 欧美电影在线| 国产精品xvideos88| 国产精品一区免费在线观看| 国产一区二区精品久久| 一区一区视频| 中文av一区二区| 久久久久久69| 亚洲激情在线| 亚洲综合日韩中文字幕v在线| 久久精品亚洲精品| 欧美成人亚洲| 国产伦精品一区二区三区在线观看| 国产午夜精品理论片a级探花 | 亚洲美女一区| 性欧美超级视频| 欧美成人免费一级人片100| 亚洲精品资源| 欧美一级视频一区二区| 欧美激情亚洲自拍| 国产亚洲视频在线| 99re6热在线精品视频播放速度| 欧美一区二区三区久久精品茉莉花| 久久综合九色综合久99| 99精品热视频| 鲁大师影院一区二区三区| 欧美色图首页| 最近中文字幕mv在线一区二区三区四区| 亚洲天堂免费观看| 免费一级欧美片在线观看| 亚洲午夜免费视频| 嫩草影视亚洲| 韩国欧美国产1区| 亚洲视频一起| 欧美风情在线观看| 亚洲欧美偷拍卡通变态| 欧美日韩国产一区二区三区| 在线观看欧美日本| 久久精品国产欧美激情| 中国女人久久久| 欧美日韩另类综合| 亚洲精品一区二区三区樱花| 久久一区二区三区四区| 午夜精品一区二区三区在线| 欧美三日本三级少妇三2023|