GCD中的使用(關(guān)于:隊(duì)列、線程袋狞、任務(wù)的理解)

版權(quán)聲明:本文為博主原創(chuàng)文章焚辅,未經(jīng)博主允許不得轉(zhuǎn)載映屋。


2017/09/06
看到一篇關(guān)于線程鎖的文章,十分的精彩同蜻。有興趣的朋友可以點(diǎn)進(jìn)去看看棚点。

下面是幾點(diǎn)自己關(guān)于線程鎖的體會(huì)

  1. 什么是線程鎖?
    一般情況下湾蔓,多個(gè)進(jìn)程可以同時(shí)訪問一個(gè)內(nèi)存瘫析。但如果中間穿插寫操作就會(huì)發(fā)生一些異常。所以需要用線程鎖默责,限制同一時(shí)刻只能有一個(gè)線程訪問一個(gè)內(nèi)存空間贬循。

  2. 讀寫是如何的實(shí)現(xiàn)?(主要講寫)

. 首先從內(nèi)存中讀取數(shù)據(jù)到寄存器,i = 0
. 在寄存器中對(duì)數(shù)據(jù)進(jìn)行寫操作 i = 1
. 將寄存器中操作后的數(shù)據(jù)寫入內(nèi)存, i = 1

從這里可以看到如果A桃序、B進(jìn)行同時(shí)進(jìn)行杖虾,A進(jìn)行寫數(shù)據(jù),B進(jìn)行讀數(shù)據(jù)媒熊。則B讀取到的數(shù)據(jù)可能是A寫之前的數(shù)據(jù)也有可能是A寫之后的數(shù)據(jù)

  1. 線程鎖有哪些類型奇适?

互斥鎖、自旋鎖芦鳍、讀寫鎖

互斥鎖嚷往、自旋鎖介紹

從 實(shí)現(xiàn)原理上來講,Mutex屬于sleep-waiting類型的鎖柠衅。例如在一個(gè)雙核的機(jī)器上有兩個(gè)線程(線程A和線程B)皮仁,它們分別運(yùn)行在Core0和 Core1上。
假設(shè)線程A想要通過pthread_mutex_lock操作去得到一個(gè)臨界區(qū)的鎖茄茁,而此時(shí)這個(gè)鎖正被線程B所持有魂贬,那么線程A就會(huì)被阻塞 (blocking),Core0 會(huì)在此時(shí)進(jìn)行上下文切換(Context Switch)將線程A置于等待隊(duì)列中裙顽,此時(shí)Core0就可以運(yùn)行其他的任務(wù)(例如另一個(gè)線程C)而不必進(jìn)行忙等待


結(jié)論:

  1. async操作開辟子線程付燥,sync操作不開辟子線程;
    2 . 同步會(huì)阻塞當(dāng)前隊(duì)列添加其他線程愈犹,異步不會(huì)阻塞當(dāng)前隊(duì)列键科。
  2. 并發(fā)隊(duì)列可以同時(shí)執(zhí)行多個(gè)線程任務(wù),串行隊(duì)列同時(shí)只能執(zhí)行一個(gè)線程任務(wù)漩怎。

多線程

在iOS 中勋颖,操作多線程主要有4個(gè)方案:

  1. PThreads:它是C語言的框架,使用起來很不方便勋锤,基本不會(huì)用饭玲。

  2. NSThread:蘋果對(duì)多線程進(jìn)行了封裝,是面向?qū)ο蟮娜础5驗(yàn)樗枰覀內(nèi)ス芾砭€程的生命周期茄厘,所以用的也不是很多矮冬。不過用它去查看當(dāng)前線程,或者讓當(dāng)前線程睡眠還是很方便的次哈。

  3. 然后是GCD:GCD是蘋果對(duì)多核運(yùn)算提出的解決方案胎署,而且gcd會(huì)自己管理生命周期,這樣可以讓我們把注意力集中在具體任務(wù)上。

  4. 最后一個(gè)是是NSOperation窑滞,它是對(duì)GCD封裝琼牧。增加一些功能。比如線程都掛起和暫停哀卫,還有線程的依賴巨坊。

不過像我最常用的還GCD,對(duì)他也最了解此改。所以就講一下它吧抱究。

GCD新增的2個(gè)概念

任務(wù):

//同步為主隊(duì)列添加了一個(gè)任務(wù),等到block結(jié)束后返回結(jié)果带斑。沒有創(chuàng)建一個(gè)新的線程
 dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"2");
 });


//異步為主隊(duì)列添加了一個(gè)任務(wù),立刻返回結(jié)果勋拟,創(chuàng)建了一個(gè)新的線程執(zhí)行任務(wù)
 dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"2");
 });

隊(duì)列

* At the core, dispatch provides serial FIFO queues to which blocks may be
 * submitted. Blocks submitted to these dispatch queues are invoked on a pool
 * of threads fully managed by the system. No guarantee is made regarding
 * which thread a block will be invoked on; however, it is guaranteed that only
 * one block submitted to the FIFO dispatch queue will be invoked at a time.
 *
 * When multiple queues have blocks to be processed, the system is free to
 * allocate additional threads to invoke the blocks concurrently. When the
 * queues become empty, these threads are automatically released.

大概意思:dispatch_sync,dispatch_async中的block代碼塊(任務(wù))會(huì)以FIFO的方式在隊(duì)列中被調(diào)用勋磕。他們將會(huì)由系統(tǒng)從線程池中隨機(jī)分配一個(gè)線程,然后執(zhí)行任務(wù)敢靡。
ps:主隊(duì)列的線程為主線程挂滓。

主隊(duì)列:dispatch_get_main_queue()

全局隊(duì)列: dispatch_get_global_queue(0, 0)

自定義隊(duì)列:
    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);//串行
    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_CONCURRENT);//并發(fā)

并發(fā)隊(duì)列:

  1. 任務(wù)以FIFO從序列中移除,然后并發(fā)運(yùn)行啸胧,一次可以調(diào)度多個(gè)赶站,可以按照任何順序完成。
  2. 可以同時(shí)執(zhí)行多個(gè)線程任務(wù)

串行隊(duì)列:

  1. 任務(wù)以FIFO從序列中一個(gè)一個(gè)執(zhí)行纺念。一次只調(diào)度一個(gè)任務(wù)
  2. 而且只會(huì)開啟一條線程

同步:

dispatch_queue_t  Aqueue = ~;

dispatch_sync(Aqueue, ^{
    NSLog(@"2");
 });

* dispatch_sync() will not return until the block has finished(同步為某隊(duì)列添加了一個(gè)任務(wù)贝椿,要知道該任務(wù)返回才能返回。)

注意:
0. 不會(huì)創(chuàng)建新的線程陷谱,所以在當(dāng)前的線程中執(zhí)行
1. 該返回可以為dispatch_async() 的返回烙博,也可以為任務(wù)執(zhí)行完畢
2. 阻塞的是當(dāng)前隊(duì)列,而不是Aqueue隊(duì)列;
3. 先阻塞當(dāng)前隊(duì)列烟逊,然后在向Aqueue隊(duì)列中添加任務(wù)渣窜。(就是因?yàn)槿绱耍栽谥麝?duì)列中同步向主隊(duì)列添加任務(wù)會(huì)造成死鎖)

異步

dispatch_queue_t  Aqueue = ~;

dispatch_async(Aqueue, ^{
    NSLog(@"2");
 });

* Calls to dispatch_async() always return immediately after the block has
* been submitted, and never wait for the block to be invoked.
(立刻返回block結(jié)果宪躯,不需要等待block中的任務(wù)被調(diào)度)

注意:
   1.  會(huì)創(chuàng)建一個(gè)新的線程去執(zhí)行任務(wù)
   2.  異步和同步一樣乔宿,影響的是當(dāng)前的隊(duì)列,對(duì)Aqueue隊(duì)列沒有影響访雪。

對(duì)同步異步详瑞、隊(duì)列掂林、任務(wù)的概念理解講完了,下面通過例子來更進(jìn)一步地理解蛤虐。

- (void)test2{


    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);//串行
    
//代碼段1
    dispatch_async(serialQueue, ^{
        NSLog(@"1");
        sleep(3);
    });
    
//代碼段2
    for(int i = 0; i < 5; i ++){
        NSLog(@"i = %d", i);
    }
    NSLog(@"0");
    
//代碼段3
    dispatch_sync(serialQueue, ^{
        NSLog(@"2");
        sleep(1);
    });
    
//代碼段4
    NSLog(@"4");
    
//代碼段5
    dispatch_async(serialQueue, ^{
        NSLog(@"3");
    });
//代碼段6
    NSLog(@"5");
 }

輸出結(jié)果:
2017-02-27 15:38:14.945 test[2527:158657] i = 0
2017-02-27 15:38:14.945 test[2527:158694] 1
2017-02-27 15:38:14.945 test[2527:158657] i = 1
2017-02-27 15:38:14.945 test[2527:158657] i = 2
2017-02-27 15:38:14.945 test[2527:158657] i = 3
2017-02-27 15:38:14.946 test[2527:158657] i = 4
2017-02-27 15:38:14.946 test[2527:158657] 0
2017-02-27 15:38:17.950 test[2527:158657] 2
2017-02-27 15:38:18.952 test[2527:158657] 4
2017-02-27 15:38:18.952 test[2527:158657] 5
2017-02-27 15:38:18.952 test[2527:158694] 3

推斷:serialQueue為一個(gè)串行隊(duì)列党饮,在串行隊(duì)列中的任務(wù)執(zhí)行FIFO。然后我看分析的代碼:

  1. 代碼1驳庭,異步為serialQueue添加一個(gè)任務(wù)(會(huì)開辟一個(gè)子線程執(zhí)行)刑顺,直接返回結(jié)果,所以同步執(zhí)行代碼段2饲常。這里的執(zhí)行結(jié)果返回順序(也只能看結(jié)果)會(huì)隨著任務(wù)消耗的時(shí)間來確定蹲堂。此時(shí)主線程:代碼段2;serialQueue線程:代碼段1

  2. 代碼3同步為serialQueue添加了打印2任務(wù)(不會(huì)開辟新的線程贝淤,所以在當(dāng)前的主線程中執(zhí)行)柒竞,所以會(huì)阻礙當(dāng)前隊(duì)列的其他任務(wù),主隊(duì)列無法添加其他任務(wù)播聪,等待打印2任務(wù)完成后執(zhí)行代碼4

  3. 碼段5異步在serialQueue隊(duì)列添加打印3任務(wù)朽基,所以會(huì)同時(shí)執(zhí)行代碼6 。輸出結(jié)果隨著代碼消耗時(shí)間決定离陶,這里添加到子線程中執(zhí)行的速度<執(zhí)行代碼6的速度稼虎。

列子二

MN3O8$(7(MAR`F0QZ7B(5(J.jpg

打印結(jié)果:1 ,3招刨, 4霎俩, 2

// 17/2/28
解釋:

  1. app啟動(dòng)的時(shí)候,會(huì)默認(rèn)創(chuàng)建一個(gè)串行隊(duì)列dispatch_get_main_queue()沉眶,我們稱之為主隊(duì)列打却,在主線程中調(diào)用。當(dāng)前主隊(duì)列有1個(gè)任務(wù):打印1谎倔,異步為為全局隊(duì)列添加一個(gè)A任務(wù)柳击,打印3,4传藏。
  2. A任務(wù)為異步在主線程中添加一個(gè)打印任務(wù)腻暮,所以當(dāng)前主線程有2個(gè)任務(wù)(如果打印3,4沒有結(jié)束的話)毯侦。根據(jù)FIFO哭靖,輸出結(jié)果1,3侈离,4 试幽;2。

例子3:

- (void)test6{
    
    dispatch_queue_t queue = dispatch_queue_create("金永峰", DISPATCH_QUEUE_CONCURRENT);

    //代碼1
    dispatch_async(queue, ^{
        
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            for(int i = 0; i < 20; i ++){
                [NSThread sleepForTimeInterval:0.5];
                NSLog(@"%@++++++++, %d", [NSThread currentThread], i);
            }
        });
        
    });
    
    //代碼2
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        //代碼4
        dispatch_sync(queue, ^{
            for(int i = 0; i < 10; i ++){
                [NSThread sleepForTimeInterval:0.5];
                NSLog(@"%@--------%d", [NSThread currentThread],i);
            }
        });
    });
}

打印結(jié)果:
2017-03-20 16:33:26.669 GCC[84715:2932251] <NSThread: 0x600000264a40>{number = 3, name = (null)}--------0
2017-03-20 16:33:26.669 GCC[84715:2932230] <NSThread: 0x60800007eac0>{number = 4, name = (null)}++++++++, 0
2017-03-20 16:33:27.171 GCC[84715:2932230] <NSThread: 0x60800007eac0>{number = 4, name = (null)}++++++++, 1
2017-03-20 16:33:27.171 GCC[84715:2932251] <NSThread: 0x600000264a40>{number = 3, name = (null)}--------1
2017-03-20 16:33:27.675 GCC[84715:2932230] <NSThread: 0x60800007eac0>{number = 4, name = (null)}++++++++, 2
2017-03-20 16:33:27.675 GCC[84715:2932251] <NSThread: 0x600000264a40>{number = 3, name = (null)}--------2
2017-03-20 16:33:28.178 GCC[84715:2932251] <NSThread: 0x600000264a40>{number = 3, name = (null)}--------3

推斷:

1.代碼1為異步為queue添加任務(wù)卦碾,所以直接返回block結(jié)果铺坞,可以直接執(zhí)行代碼2起宽,為全局創(chuàng)建1個(gè)任務(wù)。所以創(chuàng)建了2個(gè)任務(wù)(這一點(diǎn)要明確)济榨。
     
2.queu隊(duì)列里面有2個(gè)任務(wù):1. 同步創(chuàng)建一個(gè)打印任務(wù)坯沪;2:打印---;2個(gè)任務(wù)在不同的線程中擒滑,并且queue是并發(fā)對(duì)腐晾; ,所以可以同時(shí)執(zhí)行
     
3.全局隊(duì)列中也有2個(gè)任務(wù):1.同步創(chuàng)建1個(gè)打印任務(wù)丐一,2.打印+++藻糖;2個(gè)任務(wù)在不同的線程中,并且全局隊(duì)列是并發(fā)的库车,所以可以同時(shí)執(zhí)行

例子4:

- (void)test7{
    
    dispatch_queue_t queue = dispatch_queue_create("金永峰", DISPATCH_QUEUE_CONCURRENT);
  
    //代碼1
    dispatch_async(queue, ^{
        
        /** 的代碼是queue中的一個(gè)完整的任務(wù):打印\巨柒,同步在全局隊(duì)列中創(chuàng)建打印+任務(wù)  */
        for(int i = 0; i < 20; i ++){
            [NSThread sleepForTimeInterval:0.5];
            NSLog(@"%@\\\\\\", [NSThread currentThread]);
        }
        
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            for(int i = 0; i < 20; i ++){
                [NSThread sleepForTimeInterval:0.5];
                NSLog(@"%@++++++++, %d", [NSThread currentThread], i);
            }
        });
        
    });
    
    
    //代碼2
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        //代碼4
        dispatch_sync(queue, ^{
            for(int i = 0; i < 10; i ++){
                [NSThread sleepForTimeInterval:0.5];
                NSLog(@"%@--------%d", [NSThread currentThread],i);
            }
        });
    });
}



推斷:

1. 代碼1為異步執(zhí)行,所以直接返回block結(jié)果柠衍,可以直接執(zhí)行代碼2洋满,所以創(chuàng)建了2個(gè)任務(wù)(這一點(diǎn)要明確,稱為A珍坊、B任務(wù))
     
首先:
2. queue隊(duì)列中的任務(wù)有2個(gè):1芦岂、打印\\\, 同步在全局隊(duì)列中添加任務(wù),2垫蛆、打印+++。
     
3. 全局隊(duì)列中的任務(wù)1個(gè):同步創(chuàng)建1個(gè)任務(wù)
     
所以: 
 * 首先腺怯,queue(并發(fā))中的執(zhí)行代碼:同時(shí)打印\\\和打印---袱饭;
 * 等到打印\\\結(jié)束(此時(shí)queue開始執(zhí)行打印---任務(wù)),再同步在全局隊(duì)列中添加任務(wù)呛占;
 *最后全局隊(duì)列執(zhí)行任務(wù)打印++虑乖,queue執(zhí)行任務(wù)打印--


推薦的一篇文章:并發(fā) 并行 同步 異步 多線程的區(qū)別, 多線程只是我們實(shí)現(xiàn)異步的一種手段


2017/09/26


    dispatch_async(dispatch_get_main_queue(), ^{
        [self logTask:@"mainQueue"];
    });
    
    dispatch_queue_t queue = dispatch_queue_create("cx", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        [self logTask:@"sync-queue"];
    });
    


//打印-- (模擬結(jié)果)

sync-queue
sync-queue
sync-queue
sync-queue
sync-queue
·
·
·
mainQueue
mainQueue
mainQueue
mainQueue

隊(duì)列優(yōu)先級(jí)

1. 自己創(chuàng)建的隊(duì)列優(yōu)先級(jí)要高于主隊(duì)列

出現(xiàn)以上的結(jié)果是因?yàn)?/strong>:

上面這段代碼有創(chuàng)建了2個(gè)線程任務(wù)晾虑,其中有一個(gè)是同步疹味,導(dǎo)致了主隊(duì)列的死鎖。所以第一個(gè)線程任務(wù)需要等待他的完成才能繼續(xù)執(zhí)行帜篇。

下面的例子中因?yàn)樽枞牟皇侵麝?duì)列糙捺,所以可以打印任務(wù)是同步進(jìn)行的。

    dispatch_async(queue, ^{
        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            [self logTask:@"async-DISPATCH_QUEUE_PRIORITY_LOW"];
        });
    });
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [self logTask:@"mainQueue2"];
    });

//打印-- (模擬結(jié)果)

mainQueue2
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_LOW
mainQueue2
DISPATCH_QUEUE_PRIORITY_LOW
·
·
·
mainQueue2
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_LOW
mainQueue2
DISPATCH_QUEUE_PRIORITY_LOW

另外笙隙,可以看出下面2個(gè)代碼是不等價(jià)的

    dispatch_async(dispatch_get_main_queue(), ^{
        [self logTask:@"mainQueue2"];
    });
        [self logTask:@"mainQueue2"];
  1. 全局隊(duì)列的優(yōu)先級(jí)

DISPATCH_QUEUE_PRIORITY_HIGH >= DISPATCH_QUEUE_PRIORITY_DEFAULT > DISPATCH_QUEUE_PRIORITY_LOW > DISPATCH_QUEUE_PRIORITY_BACKGROUND

ps: 長(zhǎng)耗時(shí)任務(wù)可能不會(huì)嚴(yán)格遵循優(yōu)先級(jí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末洪灯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子竟痰,更是在濱河造成了極大的恐慌签钩,老刑警劉巖掏呼,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铅檩,居然都是意外死亡憎夷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門昧旨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾给,“玉大人,你說我怎么就攤上這事臼予∶鳎” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵粘拾,是天一觀的道長(zhǎng)窄锅。 經(jīng)常有香客問我,道長(zhǎng)缰雇,這世上最難降的妖魔是什么入偷? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮械哟,結(jié)果婚禮上疏之,老公的妹妹穿的比我還像新娘。我一直安慰自己暇咆,他們只是感情好锋爪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爸业,像睡著了一般其骄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上扯旷,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天拯爽,我揣著相機(jī)與錄音,去河邊找鬼钧忽。 笑死毯炮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耸黑。 我是一名探鬼主播桃煎,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼大刊!你這毒婦竟也來了备禀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎曲尸,沒想到半個(gè)月后赋续,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡另患,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年纽乱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昆箕。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸦列,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹏倘,到底是詐尸還是另有隱情薯嗤,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布纤泵,位于F島的核電站骆姐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捏题。R本人自食惡果不足惜玻褪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望公荧。 院中可真熱鬧带射,春花似錦、人聲如沸循狰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绪钥。三九已至桥爽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昧识,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工盗扒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跪楞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓侣灶,卻偏偏與公主長(zhǎng)得像甸祭,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褥影,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容