亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

詳解線程池的原理與實現(xiàn)方法

2020-02-24 14:29:44
字體:
供稿:網(wǎng)友

線程池是多線程處理的一種形式,其中任務被添加到隊列中,然后在創(chuàng)建線程后由它們自己啟動,其實每個線程使用默認堆棧大小以默認優(yōu)先級執(zhí)行,武林技術(shù)頻道小編今天為大家?guī)碓斀饩€程池的原理與實現(xiàn)方法。

一. 線程池的簡介
通常我們使用多線程的方式是,需要時創(chuàng)建一個新的線程,在這個線程里執(zhí)行特定的任務,然后在任務完成后退出。這在一般的應用里已經(jīng)能夠滿足我們應用的需求,畢竟我們并不是什么時候都需要創(chuàng)建大量的線程,并在它們執(zhí)行一個簡單的任務后銷毀。

但是在一些web、email、database等應用里,比如彩鈴,我們的應用在任何時候都要準備應對數(shù)目巨大的連接請求,同時,這些請求所要完成的任務卻又可能非常的簡單,即只占用很少的處理時間。這時,我們的應用有可能處于不停的創(chuàng)建線程并銷毀線程的狀態(tài)。雖說比起進程的創(chuàng)建,線程的創(chuàng)建時間已經(jīng)大大縮短,但是如果需要頻繁的創(chuàng)建線程,并且每個線程所占用的處理時間又非常簡短,則線程創(chuàng)建和銷毀帶給處理器的額外負擔也是很可觀的。

線程池的作用正是在這種情況下有效的降低頻繁創(chuàng)建銷毀線程所帶來的額外開銷。一般來說,線程池都是采用預創(chuàng)建的技術(shù),在應用啟動之初便預先創(chuàng)建一定數(shù)目的線程。應用在運行的過程中,需要時可以從這些線程所組成的線程池里申請分配一個空閑的線程,來執(zhí)行一定的任務,任務完成后,并不是將線程銷毀,而是將它返還給線程池,由線程池自行管理。如果線程池中預先分配的線程已經(jīng)全部分配完畢,但此時又有新的任務請求,則線程池會動態(tài)的創(chuàng)建新的線程去適應這個請求。當然,有可能,某些時段應用并不需要執(zhí)行很多的任務,導致了線程池中的線程大多處于空閑的狀態(tài),為了節(jié)省系統(tǒng)資源,線程池就需要動態(tài)的銷毀其中的一部分空閑線程。因此,線程池都需要一個管理者,按照一定的要求去動態(tài)的維護其中線程的數(shù)目。

基于上面的技術(shù),線程池將頻繁創(chuàng)建和銷毀線程所帶來的開銷分攤到了每個具體執(zhí)行的任務上,執(zhí)行的次數(shù)越多,則分攤到每個任務上的開銷就越小。

當然,如果線程創(chuàng)建銷毀所帶來的開銷與線程執(zhí)行任務的開銷相比微不足道,可以忽略不計,則線程池并沒有使用的必要。比如,F(xiàn)TP、Telnet等應用時。

二. 線程池的設計
下面利用C語言來實現(xiàn)一個簡單的線程池,為了使得這個線程池庫使用起來更加方便,特在C實現(xiàn)中加入了一些OO的思想,與Objective-C不同,它僅僅是使用了struct來模擬了c++中的類,其實這種方式在linux內(nèi)核中大量可見。

在這個庫里,與用戶有關(guān)的接口主要有:

?

?????? typedef struct tp_work_desc_s tp_work_desc; //應用線程執(zhí)行任務時所需要的一些信息
?????? typedef struct tp_work_s tp_work; //線程執(zhí)行的任務
?????? typedef struct tp_thread_info_s tp_thread_info; //描述了各個線程id,是否空閑,執(zhí)行的任務等信息
?????? typedef struct tp_thread_pool_s tp_thread_pool; // 有關(guān)線程池操作的接口信息
???????? //thread parm
?????? struct tp_work_desc_s{
????????????????? ……
??????? };
?????? //base thread struct
?????? struct tp_work_s{
????????????????? //main process function. user interface
????????????????? void (*process_job)(tp_work *this, tp_work_desc *job);
??????? };
??????? tp_thread_pool *creat_thread_pool(int min_num, int max_num);


tp_work_desc_s表示應用線程執(zhí)行任務時所需要的一些信息,會被當作線程的參數(shù)傳遞給每個線程,依據(jù)應用的不同而不同,需要用戶定義結(jié)構(gòu)的內(nèi)容。tp_work_s就是我們希望線程執(zhí)行的任務了。當我們申請分配一個新的線程時,首先要明確的指定這兩個結(jié)構(gòu),即該線程完成什么任務,并且完成這個任務需要哪些額外的信息。接口函數(shù)creat_thread_pool用來創(chuàng)建一個線程池的實例,使用時需要指定該線程池實例所能容納的最小線程數(shù)min_num和最大線程數(shù)max_num。最小線程數(shù)即線程池創(chuàng)建時預創(chuàng)建的線程數(shù)目,這個數(shù)目的大小也直接影響了線程池所能起到的效果,如果指定的太小,線程池中預創(chuàng)建的線程很快就將分配完畢并需要創(chuàng)建新的線程來適應不斷的請求,如果指定的太大,則將可能會有大量的空閑線程。我們需要根據(jù)自己應用的實際需要進行指定。描述線程池的結(jié)構(gòu)如下:

?

?

?


??????? //main thread pool struct
??????? struct tp_thread_pool_s{
???????????? TPBOOL (*init)(tp_thread_pool *this);
???????????? void (*close)(tp_thread_pool *this);
???????????? void (*process_job)(tp_thread_pool *this, tp_work *worker, tp_work_desc *job);
???????????? int? (*get_thread_by_id)(tp_thread_pool *this, int id);
???????????? TPBOOL (*add_thread)(tp_thread_pool *this);
???????????? TPBOOL (*delete_thread)(tp_thread_pool *this);
????????????? int (*get_tp_status)(tp_thread_pool *this);
????????????? int min_th_num;??????????????? //min thread number in the pool
????????????? int cur_th_num;???????????????? //current thread number in the pool
????????????? int max_th_num;???????? //max thread number in the pool
????????????? pthread_mutex_t tp_lock;
????????????? pthread_t manage_thread_id;? //manage thread id num
????????????? tp_thread_info *thread_info;?? //work thread relative thread info
};
???????? 結(jié)構(gòu)tp_thread_info_s描述了各個線程id、是否空閑、執(zhí)行的任務等信息,用戶并不需要關(guān)心它。
???????? //thread info
???????? struct tp_thread_info_s{
????????????? pthread_t????????? thread_id;???????? //thread id num
???????????? TPBOOL?????????????????? is_busy;??? //thread status:true-busy;flase-idle
???????????? pthread_cond_t????????? thread_cond;
???????????? pthread_mutex_t?????????????? thread_lock;
???????????? tp_work????????????????????? *th_work;
???????????? tp_work_desc??????????? *th_job;
???????? };


tp_thread_pool_s結(jié)構(gòu)包含了有關(guān)線程池操作的接口和變量。在使用creat_thread_pool返回一個線程池實例之后,首先要使用明確使用init接口對它進行初始化。在這個初始化過程中,線程池會預創(chuàng)建指定的最小線程數(shù)目的線程,它們都處于阻塞狀態(tài),并不損耗CPU,但是會占用一定的內(nèi)存空間。同時init也會創(chuàng)建一個線程池的管理線程,這個線程會在線程池的運行周期內(nèi)一直執(zhí)行,它將定時的查看分析線程池的狀態(tài),如果線程池中空閑的線程過多,它會刪除部分空閑的線程,當然它并不會使所有線程的數(shù)目小于指定的最小線程數(shù)。

?

在已經(jīng)創(chuàng)建并初始化了線程池之后,我們就可以指定tp_work_desc_s和tp_work_s結(jié)構(gòu),并使用線程池的process_job接口來執(zhí)行它們。這些就是我們使用這個線程池時所需要了解的所有東西。如果不再需要線程池,可以使用close接口銷毀它。

三. 實現(xiàn)代碼
Thread-pool.h(頭文件):

?

#include <stdio.h>??
#include <stdlib.h>??
#include <sys/types.h>??
#include <pthread.h>??
#include <signal.h>??

#ifndef TPBOOL??
typedef int TPBOOL;?
#endif??

#ifndef TRUE??
#define TRUE 1??
#endif??

#ifndef FALSE??
#define FALSE 0??
#endif??

#define BUSY_THRESHOLD 0.5? //(busy thread)/(all thread threshold)??
#define MANAGE_INTERVAL 5?? //tp manage thread sleep interval??

typedef struct tp_work_desc_s tp_work_desc;?
typedef struct tp_work_s tp_work;?
typedef struct tp_thread_info_s tp_thread_info;?
typedef struct tp_thread_pool_s tp_thread_pool;?

//thread parm??
struct tp_work_desc_s{?
??? char *inum; //call in??
??? char *onum; //call out??
??? int chnum;? //channel num??
};?

//base thread struct??
struct tp_work_s{?
??? //main process function. user interface??
??? void (*process_job)(tp_work *this, tp_work_desc *job);?
};?

//thread info??
struct tp_thread_info_s{?
??? pthread_t?????? thread_id;? //thread id num??
??? TPBOOL????????? is_busy;??? //thread status:true-busy;flase-idle??
??? pthread_cond_t????????? thread_cond;?????
??? pthread_mutex_t???? thread_lock;?
??? tp_work???????? *th_work;?
??? tp_work_desc??????? *th_job;?
};?

//main thread pool struct??
struct tp_thread_pool_s{?
??? TPBOOL (*init)(tp_thread_pool *this);?
??? void (*close)(tp_thread_pool *this);?
??? void (*process_job)(tp_thread_pool *this, tp_work *worker, tp_work_desc *job);?
??? int? (*get_thread_by_id)(tp_thread_pool *this, int id);?
??? TPBOOL (*add_thread)(tp_thread_pool *this);?
??? TPBOOL (*delete_thread)(tp_thread_pool *this);?
??? int (*get_tp_status)(tp_thread_pool *this);?

??? int min_th_num;???? //min thread number in the pool??
??? int cur_th_num;???? //current thread number in the pool??
??? int max_th_num;???????? //max thread number in the pool??
??? pthread_mutex_t tp_lock;?
??? pthread_t manage_thread_id; //manage thread id num??
??? tp_thread_info *thread_info;??? //work thread relative thread info??
};?

tp_thread_pool *creat_thread_pool(int min_num, int max_num);


Thread-pool.c(實現(xiàn)文件):

?

?

?


#include "thread-pool.h"??

static void *tp_work_thread(void *pthread);?
static void *tp_manage_thread(void *pthread);?

static TPBOOL tp_init(tp_thread_pool *this);?
static void tp_close(tp_thread_pool *this);?
static void tp_process_job(tp_thread_pool *this, tp_work *worker, tp_work_desc *job);?
static int? tp_get_thread_by_id(tp_thread_pool *this, int id);?
static TPBOOL tp_add_thread(tp_thread_pool *this);?
static TPBOOL tp_delete_thread(tp_thread_pool *this);?
static int? tp_get_tp_status(tp_thread_pool *this);?

/**
? * user interface. creat thread pool.
? * para:
? *???? num: min thread number to be created in the pool
? * return:
? *???? thread pool struct instance be created successfully
? */?
tp_thread_pool *creat_thread_pool(int min_num, int max_num){?
??? tp_thread_pool *this;?
??? this = (tp_thread_pool*)malloc(sizeof(tp_thread_pool));??

??? memset(this, 0, sizeof(tp_thread_pool));?

??? //init member function ponter??
??? this->init = tp_init;?
??? this->close = tp_close;?
??? this->process_job = tp_process_job;?
??? this->get_thread_by_id = tp_get_thread_by_id;?
??? this->add_thread = tp_add_thread;?
??? this->delete_thread = tp_delete_thread;?
??? this->get_tp_status = tp_get_tp_status;?

??? //init member var??
??? this->min_th_num = min_num;?
??? this->cur_th_num = this->min_th_num;?
??? this->max_th_num = max_num;?
??? pthread_mutex_init(&this->tp_lock, NULL);?

??? //malloc mem for num thread info struct??
??? if(NULL != this->thread_info)?
??????? free(this->thread_info);?
??? this->thread_info = (tp_thread_info*)malloc(sizeof(tp_thread_info)*this->max_th_num);?

??? return this;?
}?

?
/**
? * member function reality. thread pool init function.
? * para:
? *???? this: thread pool struct instance ponter
? * return:
? *???? true: successful; false: failed
? */?
TPBOOL tp_init(tp_thread_pool *this){?
??? int i;?
??? int err;?

??? //creat work thread and init work thread info??
??? for(i=0;i<this->min_th_num;i++){?
??????? pthread_cond_init(&this->thread_info[i].thread_cond, NULL);?
??????? pthread_mutex_init(&this->thread_info[i].thread_lock, NULL);?

??????? err = pthread_create(&this->thread_info[i].thread_id, NULL, tp_work_thread, this);?
??????? if(0 != err){?
??????????? printf("tp_init: creat work thread failed/n");?
??????????? return FALSE;?
??????? }?
??????? printf("tp_init: creat work thread %d/n", this->thread_info[i].thread_id);?
??? }?

??? //creat manage thread??
??? err = pthread_create(&this->manage_thread_id, NULL, tp_manage_thread, this);?
??? if(0 != err){?
??????? printf("tp_init: creat manage thread failed/n");?
??????? return FALSE;?
??? }?
??? printf("tp_init: creat manage thread %d/n", this->manage_thread_id);?

??? return TRUE;?
}?

/**
? * member function reality. thread pool entirely close function.
? * para:
? *???? this: thread pool struct instance ponter
? * return:
? */?
void tp_close(tp_thread_pool *this){?
??? int i;?

??? //close work thread??
??? for(i=0;i<this->cur_th_num;i++){?
??????? kill(this->thread_info[i].thread_id, SIGKILL);?
??????? pthread_mutex_destroy(&this->thread_info[i].thread_lock);?
??????? pthread_cond_destroy(&this->thread_info[i].thread_cond);?
??????? printf("tp_close: kill work thread %d/n", this->thread_info[i].thread_id);?
??? }?

??? //close manage thread??
??? kill(this->manage_thread_id, SIGKILL);?
??? pthread_mutex_destroy(&this->tp_lock);?
??? printf("tp_close: kill manage thread %d/n", this->manage_thread_id);?

??? //free thread struct??
??? free(this->thread_info);?
}?

/**
? * member function reality. main interface opened.?
? * after getting own worker and job, user may use the function to process the task.
? * para:
? *???? this: thread pool struct instance ponter
? * worker: user task reality.
? * job: user task para
? * return:
? */?
void tp_process_job(tp_thread_pool *this, tp_work *worker, tp_work_desc *job){?
??? int i;?
??? int tmpid;?

??? //fill this->thread_info's relative work key??
??? for(i=0;i<this->cur_th_num;i++){?
??????? pthread_mutex_lock(&this->thread_info[i].thread_lock);?
??????? if(!this->thread_info[i].is_busy){?
??????????? printf("tp_process_job: %d thread idle, thread id is %d/n", i, this->thread_info[i].thread_id);?
??????????? //thread state be set busy before work??
??????????? this->thread_info[i].is_busy = TRUE;?
??????????? pthread_mutex_unlock(&this->thread_info[i].thread_lock);?

??????????? this->thread_info[i].th_work = worker;?
??????????? this->thread_info[i].th_job = job;?

??????????? printf("tp_process_job: informing idle working thread %d, thread id is %d/n", i, this->thread_info[i].thread_id);?
??????????? pthread_cond_signal(&this->thread_info[i].thread_cond);?

??????????? return;?
??????? }?
??????? else??
??????????? pthread_mutex_unlock(&this->thread_info[i].thread_lock);??????
??? }//end of for??

??? //if all current thread are busy, new thread is created here??
??? pthread_mutex_lock(&this->tp_lock);?
??? if( this->add_thread(this) ){?
??????? i = this->cur_th_num - 1;?
??????? tmpid = this->thread_info[i].thread_id;?
??????? this->thread_info[i].th_work = worker;?
??????? this->thread_info[i].th_job = job;?
??? }?
??? pthread_mutex_unlock(&this->tp_lock);?

??? //send cond to work thread??
??? printf("tp_process_job: informing idle working thread %d, thread id is %d/n", i, this->thread_info[i].thread_id);?
??? pthread_cond_signal(&this->thread_info[i].thread_cond);?
??? return;??
}?

/**
? * member function reality. get real thread by thread id num.
? * para:
? *???? this: thread pool struct instance ponter
? * id: thread id num
? * return:
? *???? seq num in thread info struct array
? */?
int tp_get_thread_by_id(tp_thread_pool *this, int id){?
??? int i;?

??? for(i=0;i<this->cur_th_num;i++){?
??????? if(id == this->thread_info[i].thread_id)?
??????????? return i;?
??? }?

??? return -1;?
}?

/**
? * member function reality. add new thread into the pool.
? * para:
? *???? this: thread pool struct instance ponter
? * return:
? *???? true: successful; false: failed
? */?
static TPBOOL tp_add_thread(tp_thread_pool *this){?
??? int err;?
??? tp_thread_info *new_thread;?

??? if( this->max_th_num <= this->cur_th_num )?
??????? return FALSE;?

??? //malloc new thread info struct??
??? new_thread = &this->thread_info[this->cur_th_num];?

??? //init new thread's cond & mutex??
??? pthread_cond_init(&new_thread->thread_cond, NULL);?
??? pthread_mutex_init(&new_thread->thread_lock, NULL);?

??? //init status is busy??
??? new_thread->is_busy = TRUE;?

??? //add current thread number in the pool.??
??? this->cur_th_num++;?

??? err = pthread_create(&new_thread->thread_id, NULL, tp_work_thread, this);?
??? if(0 != err){?
??????? free(new_thread);?
??????? return FALSE;?
??? }?
??? printf("tp_add_thread: creat work thread %d/n", this->thread_info[this->cur_th_num-1].thread_id);?

??? return TRUE;?
}?

/**
? * member function reality. delete idle thread in the pool.
? * only delete last idle thread in the pool.
? * para:
? *???? this: thread pool struct instance ponter
? * return:
? *???? true: successful; false: failed
? */?
static TPBOOL tp_delete_thread(tp_thread_pool *this){?
??? //current thread num can't < min thread num??
??? if(this->cur_th_num <= this->min_th_num) return FALSE;?

??? //if last thread is busy, do nothing??
??? if(this->thread_info[this->cur_th_num-1].is_busy) return FALSE;?

??? //kill the idle thread and free info struct??
??? kill(this->thread_info[this->cur_th_num-1].thread_id, SIGKILL);?
??? pthread_mutex_destroy(&this->thread_info[this->cur_th_num-1].thread_lock);?
??? pthread_cond_destroy(&this->thread_info[this->cur_th_num-1].thread_cond);?

??? //after deleting idle thread, current thread num -1??
??? this->cur_th_num--;?

??? return TRUE;?
}?

/**
? * member function reality. get current thread pool status:idle, normal, busy, .etc.
? * para:
? *???? this: thread pool struct instance ponter
? * return:
? *???? 0: idle; 1: normal or busy(don't process)
? */?
static int? tp_get_tp_status(tp_thread_pool *this){?
??? float busy_num = 0.0;?
??? int i;?

??? //get busy thread number??
??? for(i=0;i<this->cur_th_num;i++){?
??????? if(this->thread_info[i].is_busy)?
??????????? busy_num++;?
??? }?

??? //0.2? or other num???
??? if(busy_num/(this->cur_th_num) < BUSY_THRESHOLD)?
??????? return 0;//idle status??
??? else?
??????? return 1;//busy or normal status??????
}?

/**
? * internal interface. real work thread.
? * para:
? *???? pthread: thread pool struct ponter
? * return:
? */?
static void *tp_work_thread(void *pthread){?
??? pthread_t curid;//current thread id??
??? int nseq;//current thread seq in the this->thread_info array??
??? tp_thread_pool *this = (tp_thread_pool*)pthread;//main thread pool struct instance??

??? //get current thread id??
??? curid = pthread_self();?

??? //get current thread's seq in the thread info struct array.??
??? nseq = this->get_thread_by_id(this, curid);?
??? if(nseq < 0)?
??????? return;?
??? printf("entering working thread %d, thread id is %d/n", nseq, curid);?

??? //wait cond for processing real job.??
??? while( TRUE ){?
??????? pthread_mutex_lock(&this->thread_info[nseq].thread_lock);?
??????? pthread_cond_wait(&this->thread_info[nseq].thread_cond, &this->thread_info[nseq].thread_lock);?
??????? pthread_mutex_unlock(&this->thread_info[nseq].thread_lock);???????

??????? printf("%d thread do work!/n", pthread_self());?

??????? tp_work *work = this->thread_info[nseq].th_work;?
??????? tp_work_desc *job = this->thread_info[nseq].th_job;?

??????? //process??
??????? work->process_job(work, job);?

??????? //thread state be set idle after work??
??????? pthread_mutex_lock(&this->thread_info[nseq].thread_lock);?????????
??????? this->thread_info[nseq].is_busy = FALSE;?
??????? pthread_mutex_unlock(&this->thread_info[nseq].thread_lock);?

??????? printf("%d do work over/n", pthread_self());?
??? }????
}?

/**
? * internal interface. manage thread pool to delete idle thread.
? * para:
? *???? pthread: thread pool struct ponter
? * return:
? */?
static void *tp_manage_thread(void *pthread){?
??? tp_thread_pool *this = (tp_thread_pool*)pthread;//main thread pool struct instance??

??? //1???
??? sleep(MANAGE_INTERVAL);?

??? do{?
??????? if( this->get_tp_status(this) == 0 ){?
??????????? do{?
??????????????? if( !this->delete_thread(this) )?
??????????????????? break;?
??????????? }while(TRUE);?
??????? }//end for if??

??????? //1???
??????? sleep(MANAGE_INTERVAL);?
??? }while(TRUE);?
}?


四. 數(shù)據(jù)庫連接池介紹???
數(shù)據(jù)庫連接是一種關(guān)鍵的有限的昂貴的資源,這一點在多用戶的網(wǎng)頁應用程序中體現(xiàn)得尤為突出。

一個數(shù)據(jù)庫連接對象均對應一個物理數(shù)據(jù)庫連接,每次操作都打開一個物理連接,使用完都關(guān)閉連接,這樣造成系統(tǒng)的 性能低下。 數(shù)據(jù)庫連接池的解決方案是在應用程序啟動時建立足夠的數(shù)據(jù)庫連接,并講這些連接組成一個連接池(簡單說:在一個“池”里放了好多半成品的數(shù)據(jù)庫聯(lián)接對象),由應用程序動態(tài)地對池中的連接進行申請、使用和釋放。對于多于連接池中連接數(shù)的并發(fā)請求,應該在請求隊列中排隊等待。并且應用程序可以根據(jù)池中連接的使用率,動態(tài)增加或減少池中的連接數(shù)。

?

連接池技術(shù)盡可能多地重用了消耗內(nèi)存地資源,大大節(jié)省了內(nèi)存,提高了服務器地服務效率,能夠支持更多的客戶服務。通過使用連接池,將大大提高程序運行效率,同時,我們可以通過其自身的管理機制來監(jiān)視數(shù)據(jù)庫連接的數(shù)量、使用情況等。

1)? 最小連接數(shù)是連接池一直保持的數(shù)據(jù)庫連接,所以如果應用程序?qū)?shù)據(jù)庫連接的使用量不大,將會有大量的數(shù)據(jù)庫連接資源被浪費;

2)? 最大連接數(shù)是連接池能申請的最大連接數(shù),如果數(shù)據(jù)庫連接請求超過此數(shù),后面的數(shù)據(jù)庫連接請求將被加入到等待隊列中,這會影響之后的數(shù)據(jù)庫操作。

其實每個行業(yè)都有發(fā)光發(fā)熱的人,我們要與時俱進,在該學習的時候要認真學習,不要讓我們學習到的專業(yè)知識成為垃圾,當然我們也不要氣餒,武林技術(shù)頻道會陪著大家。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

色噜噜狠狠色综合欧洲selulu| 精品无人区一区二区三区| 天天操夜夜爽| 国产日本欧美在线观看| 一本不卡影院| 亚洲十八**毛片| 欧美性做爰毛片| 亚洲一区二区三区无码久久| 一区二区三区波多野结衣在线观看| 不卡中文一二三区| 国产盗摄女厕一区二区三区| 欧美亚洲自拍偷拍| 成人免费毛片东京热| 久久av在线播放| 日韩麻豆第一页| 亚洲欧美日韩一区二区三区在线观看| aaaaaav| 性直播在线观看| 国产无遮挡裸体免费久久| 视频小说一区二区| 国产精品久久久免费视频| 青青久精品观看视频最新| 国产一区二区欧美日韩| 中文字幕色一区二区| 欧美精品一二三四| 日韩小视频网站| 精品美女在线播放| 日本少妇一区二区| 2019av中文字幕| 国精品人妻无码一区二区三区喝尿| 国产1区2区3区4区| 国产精品一区二区久久精品爱涩| 草民福利视频| 3d玉蒲团在线观看| 男人亚洲天堂| 久本草在线中文字幕亚洲欧美| 99青草视频在线播放视| 亚洲美女av电影| 97超级碰碰人国产在线观看| 国产九九在线观看| xxxxhd欧美精品| 激情综合网俺也去| 波多野结衣国产| 啊啊啊国产视频| 青青草精品视频| 欧美日韩一级视频| 农村老熟妇乱子伦视频| 1769国产精品视频| 国产福利在线播放麻豆| 亚洲网友自拍偷拍| 欧美伊人久久久久久午夜久久久久| 黄色网址三级| 免费中文字幕日韩欧美| 黄色成人av在线| 强伦人妻一区二区三区| 涩涩涩视频在线观看| 亚洲欧美日韩一区成人| 亚洲天堂av一区二区| 欧美视频三区在线播放| 亚洲高清免费观看高清完整版在线观看| 黄视频在线观看www| 中文字幕一区二区三区精品| 一二三四中文字幕| 亚洲第一色在线| 国产视频精品久久| 潘金莲一级淫片aaaaa| 不卡av影片| 小草在线视频在线免费视频| 国模gogo一区二区大胆私拍| 日韩电影免费网站| 蜜桃成人免费视频| 亚洲视频香蕉人妖| 91视频免费在观看| 狂野欧美性猛交xxxx巴西| 88xx成人免费观看视频库| 媚黑女一区二区| 欧美一区二区麻豆红桃视频| 国产成人精品一区二区三区网站观看| 中文在线中文资源| 精品一区亚洲| 亚洲免费不卡| 久久99国产精品二区高清软件| 国产麻豆乱码精品一区二区三区| 国产精品91久久| 成人性生交大片免费看96| а√天堂资源官网在线资源| 97影视大全免费追剧大全在线观看| 国产午夜亚洲精品羞羞网站| 黄色片网站在线免费观看| 亚洲精品极品少妇16p| 人xxxx性xxxxx欧美| 在线āv视频| 国产精品xxx在线观看| 无码人妻aⅴ一区二区三区69岛| 国产情侣小视频| 日韩欧美不卡在线观看视频| 性欧美丰满熟妇xxxx性仙踪林| 国产精品国精产品一二| 色婷婷在线视频观看| 传媒视频在线| 中文字幕丰满乱子伦无码专区| 视频在线99| 国产精品视频网站| aaa日本高清在线播放免费观看| 在线观看日韩羞羞视频| 天堂成人在线视频| 国产真实乱全部视频| 欧美疯狂party性派对| 天天做天天爱综合| 成人性教育av免费网址| 久久国产精品99久久久久久丝袜| 国产韩日精品| 久久影院理伦片| 久久久久久久久国产| 国产成人精品综合久久久| 欧美国产亚洲精品| 久草在在线视频| 91久久精品www人人做人人爽| 亚洲无线视频| 欧美日韩国产麻豆| 黄色国产网站在线播放| 一级一片免费看| 黄色污污视频软件| 午夜免费一区二区| 日韩在线视频网| 在线一级观看| 一色桃子一区二区| 黄a在线观看| 中文字幕欧美日韩一区| 超污黄色软件| 久久精品一二区| 久久天天东北熟女毛茸茸| 女女同性女同一区二区三区按摩| 中文字幕亚洲在| 一级美女在线| 国产精品久久午夜夜伦鲁鲁| 国产精品视频播放| 日本福利视频| 久久99国产精一区二区三区| 日本一区二区高清视频| 九九热视频这里只有精品| 69久久夜色精品国产7777| 亚洲成人中文字幕在线| 91国产精品视频在线| 亚洲综合免费观看高清在线观看| 日韩精品免费在线播放| 国产精品igao激情视频| 成年人免费在线视频网站| 一级片在线播放| 波多野结衣绝顶大高潮| 成人免费淫片aa视频免费| 成人精品gif动图一区| 国产精品毛片在线| 在线看片一区| 你懂的视频在线观看| 中文字幕在线视频一区二区| 一级成人免费视频| 无码人妻丰满熟妇奶水区码| 日本少妇激情视频| 依依成人精品视频| 久久久久久久久岛国免费| 国产精品一区hongkong| 亚洲一区二区在线播放| 午夜精品亚洲| 国产成人一区二区三区别| 成人午夜在线播放| 亚洲综合视频在线| 久久久久中文| 美女毛片在线看| 国产精品成人国产乱一区| 缴情综合网五月天| 秋霞久久久久久一区二区| 18欧美乱大交hd1984| 国产三级午夜理伦三级| eeuss影影院www在线播放| 成人国产激情在线| 久久精品日韩精品| 国产午夜精品一区二区三区欧美| 91伊人久久大香线蕉| 黄页网站大全在线免费观看| 欧美主播一区二区三区| 国产乱码精品一区二区三区中文| аⅴ成人天堂中文在线| 亚洲色偷偷色噜噜狠狠99网| 99高清免费国产自产拍| 久久9999久久免费精品国产| 国产精品∨欧美精品v日韩精品| 黄网站app在线观看下载视频大全官网| 网友自拍亚洲| 亚洲不卡系列| 天天av天天翘天天综合网| 一区二区三区四区视频免费观看| 在线视频中文字幕一区二区| 亚洲永久免费网站| 中文字幕福利片| 日本网站在线免费观看| 制服丝袜一区二区三区| 美女一级全黄| 米奇精品关键词| 日产精品一线二线三线芒果| 欧美videossex另类| 手机亚洲手机国产手机日韩| 亚洲成人一级片| 亚洲一级免费毛片| 韩国精品美女www爽爽爽视频| 日韩精品成人| 日韩理论片av| 麻豆91小视频| 极品美女扒开粉嫩小泬| 亚洲综合另类小说| 99久久精品一区二区| 91av资源网| www香蕉视频| 久久久女女女女999久久| 中文字幕一区二区5566日韩| 亚洲黄色视屏| 三年中国中文在线观看免费播放| 日本在线看片免费人成视1000| 亚洲精品乱码久久久久久久久久久久| 中文字幕亚洲区| 一区二区三区视频观看| 任你弄精品视频免费观看| 91九色在线观看| 强迫凌虐淫辱の牝奴在线观看| 久久网一区二区| 亚洲麻豆一区二区三区| 三级网站视频在在线播放| 羞羞答答国产精品www一本| 成人一区二区三区四区| 色综合天天综合网天天狠天天| 久久久精品免费网站| 成人动漫免费在线观看| 4hu四虎永久网址| 国产寡妇亲子伦一区二区三区四区| va中文字幕| 私人玩物在线观看| 一本在线高清不卡dvd| 欧美精品久久久久久久自慰| 国产精品一区2区3区| 欧美亚洲精品在线| 精品一区二区三区自拍图片区| 欧美成人午夜免费视在线看片| 精品国免费一区二区三区| 97精品国产97久久久久久粉红| 国产精品每日更新| 91成人精品网站| 色婷婷狠狠18禁久久| 日本天堂一区| 亚洲欧美国产一区二区| 久久神马影院| 亚洲情侣在线| 99re5久久在热线播放| 红桃视频欧美| 巨骚激情综合| 真人抽搐一进一出视频| 亚洲av成人精品一区二区三区在线播放| 欧美激情在线狂野欧美精品| 免费av网站在线| 久久成人国产精品入口| 91精品综合视频| 久久九九亚洲综合| 精品无码人妻一区二区免费蜜桃| 伊人伊人伊人久久| 国产图片一区| 亚欧色一区w666天堂| 久久精品一区二区免费播放| 菠萝蜜视频在线观看www入口| 精品三级久久久久久久电影聊斋| 欧美成人午夜视频| 最好看的2019年中文视频| 精品呦交小u女在线| 国产精品99免费看| 97精品中文字幕| 欧美乱大交xxxxxbbb| 日本免费三片免费观看| av超碰免费在线| 国产精品久久不能| 国产制服丝袜一区| 免费人成黄页网站在线一区二区| 欧美日韩黄视频| 涩涩视频免费观看| 久久国产精品1区2区3区网页| a资源在线观看| 熟妇人妻久久中文字幕| 久久久精品2019中文字幕之3| 最近中文字幕2019第二页视频| 99国产精品久久久久久久久久久| 免费看涩涩视频软件| 无码 制服 丝袜 国产 另类| 亚洲不卡一卡2卡三卡4卡5卡精品| 久久久久久久久久一级| 国产精品成人一区二区艾草| 综合色就爱涩涩涩综合婷婷| 先锋资源男人站| 中文字幕国产综合| 国产欧美久久久精品免费| 精品无码人妻一区二区免费蜜桃| 欧美一区二区三区视频免费| 丁香资源影视免费观看| 在线满18网站观看视频| huan性巨大欧美| 亚洲色成人一区二区三区小说| 国产呻吟对白刺激无套视频在线| 国产极品嫩模在线视频一区| 亚洲伦在线观看| 一区二区欧美在线观看| 国产欧美亚洲精品a| 人妻大战黑人白浆狂泄| 不卡视频在线播放| 精品无码在线观看| 久久免费福利视频| 免费在线稳定资源站| 嘿咻视频在线看| free性亚洲| 日韩一级二级三级| 亚洲欧美日韩成人高清在线一区| 久久这里只有精品视频网| 欧美性xxxx极品hd满灌| 国产精品无码久久久久| 久久久久久毛片免费看| 国产精品视频黄色| 中文字幕三区| 国产成人亚洲精品狼色在线| 欧美国产视频一区| 日本久久久精品视频| 97人摸人人澡人人人超一碰| 精品国产成人| 欧美日韩视频第一区|