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

OnTheWay2012
埋葬昨天的我,迎來(lái)重生的我!
posts - 15,  comments - 89,  trackbacks - 0
首先聲明:本文章是轉(zhuǎn)貼,為了防止自己忘記和別于查找。一切版權(quán)過(guò)作者所有。

0 前言

標(biāo)準(zhǔn)C++線程即將到來(lái)。CUJ預(yù)言它將衍生自Boost線程庫(kù),現(xiàn)在就由Bill帶領(lǐng)我們探索一下Boost線程庫(kù)。

就在幾年前,用多線程執(zhí)行程序還是一件非比尋常的事。然而今天互聯(lián)網(wǎng)應(yīng)用服務(wù)程序普遍使用多線程來(lái)提高與多客戶鏈接時(shí)的效率;為了達(dá)到最大的吞吐量,事務(wù)服務(wù)器在單獨(dú)的線程上運(yùn)行服務(wù)程序;GUI應(yīng)用程序?qū)⒛切┵M(fèi)時(shí),復(fù)雜的處理以線程的形式單獨(dú)運(yùn)行,以此來(lái)保證用戶界面能夠及時(shí)響應(yīng)用戶的操作。這樣使用多線程的例子還有很多。

但是C++標(biāo)準(zhǔn)并沒(méi)有涉及到多線程,這讓程序員們開始懷疑是否可能寫出多線程的C++程序。盡管不可能寫出符合標(biāo)準(zhǔn)的多線程程序,但是程序員們還是會(huì)使用支持多線程的操作系統(tǒng)提供的多線程庫(kù)來(lái)寫出多線程C++程序。但是這樣做至少有兩個(gè)問(wèn)題:這些庫(kù)大部分都是用C語(yǔ)言完成的,如果在C++程序中要使用這些庫(kù)就必須十分小心;還有,每一個(gè)操作系統(tǒng)都有自己的一套支持多線程的類庫(kù)。因此,這樣寫出來(lái)得代碼是沒(méi)有標(biāo)準(zhǔn)可循的,也不是到處都適用的(non-portable)。Boost線程庫(kù)就是為了解決所有這些問(wèn)題而設(shè)計(jì)的。

Boost是由C++標(biāo)準(zhǔn)委員會(huì)類庫(kù)工作組成員發(fā)起,致力于為C++開發(fā)新的類庫(kù)的組織?,F(xiàn)在它已經(jīng)有近2000名成員。許多庫(kù)都可以在Boost源碼的發(fā)布版本中找到。為了使這些類庫(kù)是線程安全的(thread-safe),Boost線程庫(kù)被創(chuàng)建了。

許多C++專家都投身于Boost線程庫(kù)的開發(fā)中。所有接口的設(shè)計(jì)都是從0開始的,并不是C線程API的簡(jiǎn)單封裝。許多C++特性(比如構(gòu)造函數(shù)和析構(gòu)函數(shù),函數(shù)對(duì)象(function object)和模板)都被使用在其中以使接口更加靈活?,F(xiàn)在的版本可以在POSIX,Win32和Macintosh Carbon平臺(tái)下工作。

1 創(chuàng)建線程

就像std::fstream類就代表一個(gè)文件一樣,boost::thread類就代表一個(gè)可執(zhí)行的線程。缺省構(gòu)造函數(shù)創(chuàng)建一個(gè)代表當(dāng)前執(zhí)行線程的實(shí)例。一個(gè)重載的構(gòu)造函數(shù)以一個(gè)不需任何參數(shù)的函數(shù)對(duì)象作為參數(shù),并且沒(méi)有返回值。這個(gè)構(gòu)造函數(shù)創(chuàng)建一個(gè)新的可執(zhí)行線程,它調(diào)用了那個(gè)函數(shù)對(duì)象。

起先,大家認(rèn)為傳統(tǒng)C創(chuàng)建線程的方法似乎比這樣的設(shè)計(jì)更有用,因?yàn)镃創(chuàng)建線程的時(shí)候會(huì)傳入一個(gè)void*指針,通過(guò)這種方法就可以傳入數(shù)據(jù)。然而,由于Boost線程庫(kù)是使用函數(shù)對(duì)象來(lái)代替函數(shù)指針,那么函數(shù)對(duì)象本身就可以攜帶線程所需的數(shù)據(jù)。這種方法更具靈活性,也是類型安全(type-safe)的。當(dāng)和Boost.Bind這樣的功能庫(kù)一起使用時(shí),這樣的方法就可以讓你傳遞任意數(shù)量的數(shù)據(jù)給新建的線程。

目前,由Boost線程庫(kù)創(chuàng)建的線程對(duì)象功能還不是很強(qiáng)大。事實(shí)上它只能做兩項(xiàng)操作。線程對(duì)象可以方便使用==和!=進(jìn)行比較來(lái)確定它們是否是代表同一個(gè)線程;你還可以調(diào)用boost::thread::join來(lái)等待線程執(zhí)行完畢。其他一些線程庫(kù)可以讓你對(duì)線程做一些其他操作(比如設(shè)置優(yōu)先級(jí),甚至是取消線程)。然而,由于要在普遍適用(portable)的接口中加入這些操作不是簡(jiǎn)單的事,目前仍在討論如何將這些操組加入到Boost線程庫(kù)中。

Listing1展示了boost::thread類的一個(gè)最簡(jiǎn)單的用法。 新建的線程只是簡(jiǎn)單的在std::out上打印“hello,world”,main函數(shù)在它執(zhí)行完畢之后結(jié)束。


例1:

#include <boost/thread/thread.hpp>
#include <iostream>
void hello()
{
std::cout <<
"Hello world, I'm a thread!"
<< std::endl;
}
int main(int argc, char* argv[])
{
boost::thread thrd(&hello);
thrd.join();
return 0;
}

2 互斥體

任何寫過(guò)多線程程序的人都知道避免不同線程同時(shí)訪問(wèn)共享區(qū)域的重要性。如果一個(gè)線程要改變共享區(qū)域中某個(gè)數(shù)據(jù),而與此同時(shí)另一線程正在讀這個(gè)數(shù)據(jù),那么結(jié)果將是未定義的。為了避免這種情況的發(fā)生就要使用一些特殊的原始類型和操作。其中最基本的就是互斥體(mutex,mutual exclusion的縮寫)。一個(gè)互斥體一次只允許一個(gè)線程訪問(wèn)共享區(qū)。當(dāng)一個(gè)線程想要訪問(wèn)共享區(qū)時(shí),首先要做的就是鎖?。╨ock)互斥體。如果其他的線程已經(jīng)鎖住了互斥體,那么就必須先等那個(gè)線程將互斥體解鎖,這樣就保證了同一時(shí)刻只有一個(gè)線程能訪問(wèn)共享區(qū)域。

互斥體的概念有不少變種。Boost線程庫(kù)支持兩大類互斥體,包括簡(jiǎn)單互斥體(simple mutex)和遞歸互斥體(recursive mutex)。如果同一個(gè)線程對(duì)互斥體上了兩次鎖,就會(huì)發(fā)生死鎖(deadlock),也就是說(shuō)所有的等待解鎖的線程將一直等下去。有了遞歸互斥體,單個(gè)線程就可以對(duì)互斥體多次上鎖,當(dāng)然也必須解鎖同樣次數(shù)來(lái)保證其他線程可以對(duì)這個(gè)互斥體上鎖。

在這兩大類互斥體中,對(duì)于線程如何上鎖還有多個(gè)變種。一個(gè)線程可以有三種方法來(lái)對(duì)一個(gè)互斥體加鎖:

  1. 一直等到?jīng)]有其他線程對(duì)互斥體加鎖。
  2. 如果有其他互斥體已經(jīng)對(duì)互斥體加鎖就立即返回。
  3. 一直等到?jīng)]有其他線程互斥體加鎖,直到超時(shí)。

似乎最佳的互斥體類型是遞歸互斥體,它可以使用所有三種上鎖形式。然而每一個(gè)變種都是有代價(jià)的。所以Boost線程庫(kù)允許你根據(jù)不同的需要使用最有效率的互斥體類型。Boost線程庫(kù)提供了6中互斥體類型,下面是按照效率進(jìn)行排序:

boost::mutex,
boost::try_mutex,
boost::timed_mutex,
boost::recursive_mutex,
boost::recursive_try_mutex,
boost::recursive_timed_mutex 
如果互斥體上鎖之后沒(méi)有解鎖就會(huì)發(fā)生死鎖。這是一個(gè)很普遍的錯(cuò)誤,Boost線程庫(kù)就是要將其變成不可能(至少時(shí)很困難)。直接對(duì)互斥體上鎖和解鎖對(duì)于Boost線程庫(kù)的用戶來(lái)說(shuō)是不可能的。mutex類通過(guò)teypdef定義在RAII中實(shí)現(xiàn)的類型來(lái)實(shí)現(xiàn)互斥體的上鎖和解鎖。這也就是大家知道的Scope Lock模式。為了構(gòu)造這些類型,要傳入一個(gè)互斥體的引用。構(gòu)造函數(shù)對(duì)互斥體加鎖,析構(gòu)函數(shù)對(duì)互斥體解鎖。C++保證了析構(gòu)函數(shù)一定會(huì)被調(diào)用,所以即使是有異常拋出,互斥體也總是會(huì)被正確的解鎖。

這種方法保證正確的使用互斥體。然而,有一點(diǎn)必須注意:盡管Scope Lock模式可以保證互斥體被解鎖,但是它并沒(méi)有保證在異常拋出之后貢獻(xiàn)資源仍是可用的。所以就像執(zhí)行單線程程序一樣,必須保證異常不會(huì)導(dǎo)致程序狀態(tài)異常。另外,這個(gè)已經(jīng)上鎖的對(duì)象不能傳遞給另一個(gè)線程,因?yàn)樗鼈兙S護(hù)的狀態(tài)并沒(méi)有禁止這樣做。

List2給出了一個(gè)使用boost::mutex的最簡(jiǎn)單的例子。例子中共創(chuàng)建了兩個(gè)新的線程,每個(gè)線程都有10次循環(huán),在std::cout上打印出線程id和當(dāng)前循環(huán)的次數(shù),而main函數(shù)等待這兩個(gè)線程執(zhí)行完才結(jié)束。std::cout就是共享資源,所以每一個(gè)線程都使用一個(gè)全局互斥體來(lái)保證同時(shí)只有一個(gè)線程能向它寫入。

許多讀者可能已經(jīng)注意到List2中傳遞數(shù)據(jù)給線程還必須的手工寫一個(gè)函數(shù)。盡管這個(gè)例子很簡(jiǎn)單,如果每一次都要寫這樣的代碼實(shí)在是讓人厭煩的事。別急,有一種簡(jiǎn)單的解決辦法。函數(shù)庫(kù)允許你通過(guò)將另一個(gè)函數(shù)綁定,并傳入調(diào)用時(shí)需要的數(shù)據(jù)來(lái)創(chuàng)建一個(gè)新的函數(shù)。 List3向你展示了如何使用Boost.Bind庫(kù)來(lái)簡(jiǎn)化List2中的代碼,這樣就不必手工寫這些函數(shù)對(duì)象了。

例2:

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
boost::mutex io_mutex;
struct count
{
count(int id) : id(id) { }
void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": "
<< i << std::endl;
}
}
int id;
};
int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}

例3: // 這個(gè)例子和例2一樣,除了使用Boost.Bind來(lái)簡(jiǎn)化創(chuàng)建線程攜帶數(shù)據(jù),避免使用函數(shù)對(duì)象

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}

3 條件變量

有的時(shí)候僅僅依靠鎖住共享資源來(lái)使用它是不夠的。有時(shí)候共享資源只有某些狀態(tài)的時(shí)候才能夠使用。比方說(shuō),某個(gè)線程如果要從堆棧中讀取數(shù)據(jù),那么如果棧中沒(méi)有數(shù)據(jù)就必須等待數(shù)據(jù)被壓棧。這種情況下的同步使用互斥體是不夠的。另一種同步的方式--條件變量,就可以使用在這種情況下。

條件變量的使用總是和互斥體及共享資源聯(lián)系在一起的。線程首先鎖住互斥體,然后檢驗(yàn)共享資源的狀態(tài)是否處于可使用的狀態(tài)。如果不是,那么線程就要等待條件變量。要指向這樣的操作就必須在等待的時(shí)候?qū)⒒コ怏w解鎖,以便其他線程可以訪問(wèn)共享資源并改變其狀態(tài)。它還得保證從等到得線程返回時(shí)互斥體是被上鎖得。當(dāng)另一個(gè)線程改變了共享資源的狀態(tài)時(shí),它就要通知正在等待條件變量得線程,并將之返回等待的線程。

List4是一個(gè)使用了boost::condition的簡(jiǎn)單例子。有一個(gè)實(shí)現(xiàn)了有界緩存區(qū)的類和一個(gè)固定大小的先進(jìn)先出的容器。由于使用了互斥體boost::mutex,這個(gè)緩存區(qū)是線程安全的。put和get使用條件變量來(lái)保證線程等待完成操作所必須的狀態(tài)。有兩個(gè)線程被創(chuàng)建,一個(gè)在buffer中放入100個(gè)整數(shù),另一個(gè)將它們從buffer中取出。這個(gè)有界的緩存一次只能存放10個(gè)整數(shù),所以這兩個(gè)線程必須周期性的等待另一個(gè)線程。為了驗(yàn)證這一點(diǎn),put和get在std::cout中輸出診斷語(yǔ)句。最后,當(dāng)兩個(gè)線程結(jié)束后,main函數(shù)也就執(zhí)行完畢了。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <iostream>
const int BUF_SIZE = 10;
const int ITERS = 100;
boost::mutex io_mutex;
class buffer
{
public:
typedef boost::mutex::scoped_lock
scoped_lock;
buffer()
: p(0), c(0), full(0)
{
}
void put(int m)
{
scoped_lock lock(mutex);
if (full == BUF_SIZE)
{
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout <<
"Buffer is full. Waiting..."
<< std::endl;
}
while (full == BUF_SIZE)
cond.wait(lock);
}
buf[p] = m;
p = (p+1) % BUF_SIZE;
++full;
cond.notify_one();
}
int get()
{
scoped_lock lk(mutex);
if (full == 0)
{
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout <<
"Buffer is empty. Waiting..."
<< std::endl;
}
while (full == 0)
cond.wait(lk);
}
int i = buf[c];
c = (c+1) % BUF_SIZE;
--full;
cond.notify_one();
return i;
}
private:
boost::mutex mutex;
boost::condition cond;
unsigned int p, c, full;
int buf[BUF_SIZE];
};
buffer buf;
void writer()
{
for (int n = 0; n < ITERS; ++n)
{
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << "sending: "
<< n << std::endl;
}
buf.put(n);
}
}
void reader()
{
for (int x = 0; x < ITERS; ++x)
{
int n = buf.get();
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << "received: "
<< n << std::endl;
}
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(&reader);
boost::thread thrd2(&writer);
thrd1.join();
thrd2.join();
return 0;
}

4 線程局部存儲(chǔ)

大多數(shù)函數(shù)都不是可重入的。這也就是說(shuō)在某一個(gè)線程已經(jīng)調(diào)用了一個(gè)函數(shù)時(shí),如果你再調(diào)用同一個(gè)函數(shù),那么這樣是不安全的。一個(gè)不可重入的函數(shù)通過(guò)連續(xù)的調(diào)用來(lái)保存靜態(tài)變量或者是返回一個(gè)指向靜態(tài)數(shù)據(jù)的指針。 舉例來(lái)說(shuō),std::strtok就是不可重入的,因?yàn)樗褂渺o態(tài)變量來(lái)保存要被分割成符號(hào)的字符串。

有兩種方法可以讓不可重用的函數(shù)變成可重用的函數(shù)。第一種方法就是改變接口,用指針或引用代替原先使用靜態(tài)數(shù)據(jù)的地方。比方說(shuō),POSIX定義了strok_r,std::strtok中的一個(gè)可重入的變量,它用一個(gè)額外的char**參數(shù)來(lái)代替靜態(tài)數(shù)據(jù)。這種方法很簡(jiǎn)單,而且提供了可能的最佳效果。但是這樣必須改變公共接口,也就意味著必須改代碼。另一種方法不用改變公有接口,而是用本地存儲(chǔ)線程(thread local storage)來(lái)代替靜態(tài)數(shù)據(jù)(有時(shí)也被成為特殊線程存儲(chǔ),thread-specific storage)。

Boost線程庫(kù)提供了智能指針boost::thread_specific_ptr來(lái)訪問(wèn)本地存儲(chǔ)線程。每一個(gè)線程第一次使用這個(gè)智能指針的實(shí)例時(shí),它的初值是NULL,所以必須要先檢查這個(gè)它的只是否為空,并且為它賦值。Boost線程庫(kù)保證本地存儲(chǔ)線程中保存的數(shù)據(jù)會(huì)在線程結(jié)束后被清除。

List5是一個(gè)使用boost::thread_specific_ptr的簡(jiǎn)單例子。其中創(chuàng)建了兩個(gè)線程來(lái)初始化本地存儲(chǔ)線程,并有10次循環(huán),每一次都會(huì)增加智能指針指向的值,并將其輸出到std::cout上(由于std::cout是一個(gè)共享資源,所以通過(guò)互斥體進(jìn)行同步)。main線程等待這兩個(gè)線程結(jié)束后就退出。從這個(gè)例子輸出可以明白的看出每個(gè)線程都處理屬于自己的數(shù)據(jù)實(shí)例,盡管它們都是使用同一個(gè)boost::thread_specific_ptr。

例5:

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>
boost::mutex io_mutex;
boost::thread_specific_ptr<int> ptr;
struct count
{
count(int id) : id(id) { }
void operator()()
{
if (ptr.get() == 0)
ptr.reset(new int(0));
for (int i = 0; i < 10; ++i)
{
(*ptr)++;
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": "
<< *ptr << std::endl;
}
}
int id;
};
int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}

5 僅運(yùn)行一次的例程

還有一個(gè)問(wèn)題沒(méi)有解決:如何使得初始化工作(比如說(shuō)構(gòu)造函數(shù))也是線程安全的。比方說(shuō),如果一個(gè)引用程序要產(chǎn)生唯一的全局的對(duì)象,由于實(shí)例化順序的問(wèn)題,某個(gè)函數(shù)會(huì)被調(diào)用來(lái)返回一個(gè)靜態(tài)的對(duì)象,它必須保證第一次被調(diào)用時(shí)就產(chǎn)生這個(gè)靜態(tài)的對(duì)象。這里的問(wèn)題就是如果多個(gè)線程同時(shí)調(diào)用了這個(gè)函數(shù),那么這個(gè)靜態(tài)對(duì)象的構(gòu)造函數(shù)就會(huì)被調(diào)用多次,這樣錯(cuò)誤產(chǎn)生了。

解決這個(gè)問(wèn)題的方法就是所謂的“一次實(shí)現(xiàn)”(once routine)。“一次實(shí)現(xiàn)”在一個(gè)應(yīng)用程序只能執(zhí)行一次。如果多個(gè)線程想同時(shí)執(zhí)行這個(gè)操作,那么真正執(zhí)行的只有一個(gè),而其他線程必須等這個(gè)操作結(jié)束。為了保證它只被執(zhí)行一次,這個(gè)routine由另一個(gè)函數(shù)間接的調(diào)用,而這個(gè)函數(shù)傳給它一個(gè)指針以及一個(gè)標(biāo)志著這個(gè)routine是否已經(jīng)被調(diào)用的特殊標(biāo)志。這個(gè)標(biāo)志是以靜態(tài)的方式初始化的,這也就保證了它在編譯期間就被初始化而不是運(yùn)行時(shí)。因此也就沒(méi)有多個(gè)線程同時(shí)將它初始化的問(wèn)題了。Boost線程庫(kù)提供了boost::call_once來(lái)支持“一次實(shí)現(xiàn)”,并且定義了一個(gè)標(biāo)志boost::once_flag及一個(gè)初始化這個(gè)標(biāo)志的宏BOOST_ONCE_INIT。

List6是一個(gè)使用了boost::call_once的例子。其中定義了一個(gè)靜態(tài)的全局整數(shù),初始值為0;還有一個(gè)由BOOST_ONCE_INIT初始化的靜態(tài)boost::once_flag實(shí)例。main函數(shù)創(chuàng)建了兩個(gè)線程,它們都想通過(guò)傳入一個(gè)函數(shù)調(diào)用boost::call_once來(lái)初始化這個(gè)全局的整數(shù),這個(gè)函數(shù)是將它加1。main函數(shù)等待著兩個(gè)線程結(jié)束,并將最后的結(jié)果輸出的到std::cout。由最后的結(jié)果可以看出這個(gè)操作確實(shí)只被執(zhí)行了一次,因?yàn)樗闹凳?。

#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <iostream>
int i = 0;
boost::once_flag flag =
BOOST_ONCE_INIT;
void init()
{
++i;
}
void thread()
{
boost::call_once(&init, flag);
}
int main(int argc, char* argv[])
{
boost::thread thrd1(&thread);
boost::thread thrd2(&thread);
thrd1.join();
thrd2.join();
std::cout << i << std::endl;
return 0;
}

6 Boost線程庫(kù)的未來(lái)

Boost線程庫(kù)正在計(jì)劃加入一些新特性。其中包括boost::read_write_mutex,它可以讓多個(gè)線程同時(shí)從共享區(qū)中讀取數(shù)據(jù),但是一次只可能有一個(gè)線程向共享區(qū)寫入數(shù)據(jù);boost::thread_barrier,它使得一組線程處于等待狀態(tài),知道所有得線程都都進(jìn)入了屏障區(qū);boost::thread_pool,他允許執(zhí)行一些小的routine而不必每一都要?jiǎng)?chuàng)建或是銷毀一個(gè)線程。

Boost線程庫(kù)已經(jīng)作為標(biāo)準(zhǔn)中的類庫(kù)技術(shù)報(bào)告中的附件提交給C++標(biāo)準(zhǔn)委員會(huì),它的出現(xiàn)也為下一版C++標(biāo)準(zhǔn)吹響了第一聲號(hào)角。委員會(huì)成員對(duì)Boost線程庫(kù)的初稿給予了很高的評(píng)價(jià),當(dāng)然他們還會(huì)考慮其他的多線程庫(kù)。他們對(duì)在C++標(biāo)準(zhǔn)中加入對(duì)多線程的支持非常感興趣。從這一點(diǎn)上也可以看出,多線程在C++中的前途一片光明。

posted on 2010-06-18 22:23 OnTheWay 閱讀(297) 評(píng)論(0)  編輯 收藏 引用

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理



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

常用鏈接

留言簿(4)

隨筆分類

隨筆檔案

友情連接

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲人永久免费| 亚洲精品美女久久久久| 久久免费视频观看| 亚洲国产精品一区二区www| 亚洲精品一区在线观看香蕉| 国产一区二区高清不卡| 亚洲精品中文字幕女同| 狠狠色狠狠色综合| 亚洲视频图片小说| 亚洲国产91| 亚洲无毛电影| 亚洲精选国产| 久久九九99视频| 亚洲欧美在线观看| 欧美精品七区| 奶水喷射视频一区| 国产精品成av人在线视午夜片| 狼狼综合久久久久综合网 | 亚洲视屏一区| 亚洲免费av电影| 久久精品人人做人人综合 | 欧美影院成人| 欧美色区777第一页| 美女视频网站黄色亚洲| 国产乱人伦精品一区二区| 亚洲三级性片| 亚洲精品一区在线| 亚洲一区二区视频在线观看| 99re热这里只有精品免费视频| 久久视频在线视频| 午夜亚洲福利在线老司机| 美女脱光内衣内裤视频久久影院 | 久久九九有精品国产23| 欧美午夜片欧美片在线观看| 亚洲二区视频| 亚洲三级性片| 欧美大片免费久久精品三p | 欧美一区二区播放| 国产精品劲爆视频| 一区二区三区日韩欧美精品| 亚洲视频在线二区| 久久精品视频导航| 欧美 日韩 国产一区二区在线视频 | 中文日韩在线| 欧美日韩在线观看一区二区| 亚洲精品麻豆| 亚洲一二三四久久| 国产精品videossex久久发布| 亚洲高清在线视频| 一本一道久久综合狠狠老精东影业| 欧美激情导航| 99视频精品全部免费在线| 中文在线一区| 欧美性一二三区| 亚洲欧美日韩国产一区二区三区| 亚洲小少妇裸体bbw| 国产精品久久久久久久久动漫| 亚洲视频在线观看三级| 欧美亚洲一级片| 国产一区二区三区在线观看视频 | 欧美在线一二三四区| 另类亚洲自拍| 亚洲乱码精品一二三四区日韩在线| 免费观看一区| 日韩一区二区精品视频| 性色av一区二区三区| 在线播放豆国产99亚洲| 欧美另类综合| 999亚洲国产精| 欧美一区二区在线播放| 精品av久久707| 欧美黄网免费在线观看| 亚洲男女自偷自拍| 久久精品国产v日韩v亚洲| 伊人婷婷久久| 欧美午夜电影在线观看| 久久gogo国模啪啪人体图| 亚洲国语精品自产拍在线观看| 亚洲欧美日韩天堂| …久久精品99久久香蕉国产| 欧美日韩日日骚| 久久精品国产亚洲精品| 亚洲毛片av在线| 久久久亚洲人| 亚洲一区在线直播| 亚洲激情在线观看| 国产女主播一区二区| 欧美成人精品高清在线播放| 欧美一级久久久| 最新中文字幕亚洲| 噜噜噜在线观看免费视频日韩| 一本色道久久综合狠狠躁篇怎么玩 | 在线观看视频亚洲| 国产精品国产a| 快she精品国产999| 亚洲欧美日韩精品久久奇米色影视| 欧美激情二区三区| 久久久99免费视频| 亚洲专区免费| 日韩一级大片| 国产一区在线看| 国产精品香蕉在线观看| 欧美日本一道本| 免费日韩视频| 美女日韩欧美| 日韩视频二区| 亚洲欧洲一区二区三区久久| 亚洲经典三级| 亚洲精品视频在线| 一区二区三区视频免费在线观看| 一区二区三区日韩精品| 亚洲午夜视频在线观看| 午夜精品成人在线| 久久久久九九九| 美乳少妇欧美精品| 欧美日本韩国一区二区三区| 欧美色视频一区| 国产女主播视频一区二区| 黑人巨大精品欧美一区二区小视频| 狠狠色综合色区| 亚洲精品日本| 亚洲午夜电影在线观看| 香蕉亚洲视频| 免费日韩一区二区| 亚洲精品三级| 一区二区三区国产盗摄| 亚洲欧美在线免费| 久久亚洲精品中文字幕冲田杏梨| 女人香蕉久久**毛片精品| 欧美日韩高清在线| 国产午夜精品一区二区三区欧美 | 亚洲欧美日韩国产中文| 羞羞视频在线观看欧美| 老司机午夜精品视频| 亚洲国产成人精品视频 | 999在线观看精品免费不卡网站| 一本色道久久综合亚洲精品不卡| 亚洲欧美在线网| 久久综合亚州| 欧美香蕉视频| 精品成人在线观看| 一区二区不卡在线视频 午夜欧美不卡在 | 国产亚洲毛片| 亚洲精品视频免费观看| 亚洲欧美日韩视频一区| 欧美成人免费网| 夜夜嗨av色一区二区不卡| 欧美一二三区在线观看| 欧美精品在线看| 黄色一区二区在线观看| 中文av字幕一区| 欧美高清视频在线| 亚洲免费在线播放| 欧美激情综合五月色丁香| 国产欧美在线视频| 99国产精品国产精品久久| 久久国产精品72免费观看| 亚洲三级免费| 久久精品视频网| 国产精品扒开腿做爽爽爽视频 | 性欧美xxxx大乳国产app| 欧美二区在线| 欧美亚洲色图校园春色| 欧美人与禽猛交乱配| 伊人天天综合| 久久精品女人天堂| 亚洲一级片在线看| 欧美日韩在线精品| 亚洲精品久久在线| 免费黄网站欧美| 欧美一区二区观看视频| 欧美视频一二三区| 亚洲精品在线电影| 欧美国产乱视频| 久久精品免费观看| 国产一区二区三区精品久久久| 亚洲欧美影院| 亚洲最黄网站| 欧美剧在线观看| 亚洲欧洲一区二区三区| 免费在线亚洲| 久久这里有精品15一区二区三区 | 亚洲一区二区在线看| 亚洲日本激情| 欧美激情视频网站| 日韩视频一区二区| 亚洲人成网站在线播| 欧美久久视频| 一区二区三区四区国产精品| 亚洲精品偷拍| 国产精品mm| 亚洲桃花岛网站| 一本色道综合亚洲| 国产精品久久久久久久午夜片| 亚洲自拍高清| 亚洲综合色激情五月| 国产日韩欧美在线播放不卡| 久久国产一区二区三区| 欧美一区高清| 在线视频成人|