一次性搞懂 GCD的所有用法

GCD.png
講GCD之前渗蟹,必須得說說線程

線程(英語:thread)是操作系統(tǒng)能夠進行運算調(diào)度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流吁津,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)堕扶。 以下是 iOS 中 4 套多線程方案

  • Pthreads : POSIX線程(POSIX threads)碍脏,簡稱Pthreads,是線程的POSIX標(biāo)準(zhǔn)稍算。該標(biāo)準(zhǔn)定義了創(chuàng)建和操縱線程的一整套API典尾。在類Unix操作系統(tǒng)(Unix、Linux糊探、Mac OS X等)中钾埂,都使用Pthreads作為操作系統(tǒng)的線程。
  • NSThread : 是三種方法里面相對輕量級的科平,但需要管理線程的生命周期褥紫、同步、加鎖問題瞪慧,這會導(dǎo)致一定的性能開銷
  • Grand Central Dispatch(簡稱GCD髓考,iOS4才開始支持):提供了一些新特性、運行庫來支持多核并行編程汞贸,它的關(guān)注點更高:如何在多個cpu上提升效率
  • NSOperation & NSOperationQueue : 蘋果公司對 GCD 的封裝绳军,完全面向?qū)ο螅琋SOperation以面向?qū)ο蟮姆绞椒庋b了需要執(zhí)行的操作矢腻,不必關(guān)心線程管理门驾、同步等問題。NSOperation是一個抽象基類多柑,iOS提供了兩種默認(rèn)實現(xiàn):NSInvocationOperation和NSBlockOperation奶是,當(dāng)然也可以自定義NSOperation
Pthreads的函數(shù)我們幾乎不會用到
NSThread倒是有一些API,使用很方便來看一下
//取消線程
- (void)cancel;

//啟動線程
- (void)start;

//判斷某個線程的狀態(tài)的屬性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;

//設(shè)置和獲取線程名字
-(void)setName:(NSString *)n;
-(NSString *)name;

//獲取當(dāng)前線程信息
+ (NSThread *)currentThread;

//獲取主線程信息
+ (NSThread *)mainThread;

//使當(dāng)前線程暫停一段時間竣灌,或者暫停到某個時刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;

主角出場

Grand Central Dispatch

GCD開源地址聂沙。
GCD的好處在于它不需要管理線程的生命周期,線程的創(chuàng)建與分配初嘹,它是蘋果為多核的并行運算提出的解決方案及汉,所以會自動合理地利用更多的CPU內(nèi)核。

來看看怎么使用GCD

描述 說明
queue 隊列
main 主隊列
global 全局隊列
dispatch_queue_t 描述隊列
dispatch_block_t 描述任務(wù)
dispatch_once_t 描述一次性
dispatch_time_t 描述時間
dispatch_group_t 描述隊列組
dispatch_semaphore_t 描述信號量
函數(shù) 說明
dispatch_sync() 同步執(zhí)行
dispatch_async() 異步執(zhí)行
dispatch_after() 延時執(zhí)行
dispatch_once() 一次性執(zhí)行
dispatch_apply() 快速遍歷
dispatch_queue_create() 創(chuàng)建隊列
dispatch_group_create() 創(chuàng)建隊列組
dispatch_group_async() 提交任務(wù)到隊列組
dispatch_group_enter()
dispatch_group_leave() 進入屯烦、離開組隊列
dispatch_group_notify() 監(jiān)聽隊列組執(zhí)行完
dispatch_group_wait() 設(shè)置等待時間
  • 同步異步線程創(chuàng)建
//同步線程
dispatch_sync(隊列, ^(block)) 阻塞線程
//異步線程
dispatch_async(隊列, ^(block)) 不阻塞線程
  • 系統(tǒng)標(biāo)準(zhǔn)兩個隊列
//全局隊列坷随,一個并行的隊列
dispatch_get_global_queue
//主隊列,主線程中的唯一隊列驻龟,一個串行隊列
dispatch_get_main_queue
  • 自定義隊列
//串行隊列
dispatch_queue_create("com.boundless.serial", DISPATCH_QUEUE_SERIAL)
dispatch_queue_create("com.boundless.serial", NULL) // NULL默認(rèn)為串行
//并行隊列
dispatch_queue_create("com.boundless.concurrent", DISPATCH_QUEUE_CONCURRENT)

//隊列優(yōu)先級
* DISPATCH_QUEUE_PRIORITY_HIGH   優(yōu)先級高
* DISPATCH_QUEUE_PRIORITY_DEFAULT  優(yōu)先級默認(rèn)
* DISPATCH_QUEUE_PRIORITY_LOW   優(yōu)先級低
* DISPATCH_QUEUE_PRIORITY_BACKGROUND 優(yōu)先級最低  表示用戶不會察覺的任務(wù)温眉,使用它來處理預(yù)加載,或者不需要用戶交互和對時間不敏感的任務(wù)

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 可直接設(shè)置優(yōu)先級
自定義隊列優(yōu)先級設(shè)置方法
   dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);
    dispatch_queue_t custom_concrrent_priority_queue = dispatch_queue_create("com.boundless.concurrent", attr);

何時使用何種隊列類型

  • 主隊列(順序):隊列中有任務(wù)完成需要更新UI時翁狐,dispatch_after在這種類型中使用类溢。
  • 并發(fā)隊列:用來執(zhí)行與UI無關(guān)的后臺任務(wù),dispatch_sync放在這里露懒,方便等待任務(wù)完成進行后續(xù)處理或和dispatch barrier同步闯冷。dispatch groups放在這里也不錯。
  • 自定義順序隊列:順序執(zhí)行后臺任務(wù)并追蹤它時隐锭。這樣做同時只有一個任務(wù)在執(zhí)行可以防止資源競爭窃躲。dipatch barriers解決讀寫鎖問題的放在這里處理。dispatch groups也是放在這里钦睡。

看代碼

    /** 全局并行隊列 */
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    /** 主串行隊列 */
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    /** 自定義串行隊列 */
    dispatch_queue_t custom_serial_queue = dispatch_queue_create("com.boundless.serial", DISPATCH_QUEUE_CONCURRENT);
    /** 自定義并發(fā)隊列 */
    dispatch_queue_t custom_concrrent_queue = dispatch_queue_create("com.boundless.concurrent", DISPATCH_QUEUE_CONCURRENT);
    /** 自定義隊列設(shè)置優(yōu)先級 */
    dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);
    dispatch_queue_t custom_concrrent_priority_queue = dispatch_queue_create("com.boundless.concurrent", attr);
    
    /** 任務(wù)(^{})在全局隊列(global_queue)中同步執(zhí)行(dispatch_sync) */
    dispatch_sync(global_queue, ^{
        NSLog(@"執(zhí)行任務(wù)");
    });
    /** 任務(wù)(^{})在全主隊列(main_queue)中同步執(zhí)行(dispatch_sync) */
    dispatch_sync(main_queue, ^{
        NSLog(@"執(zhí)行任務(wù)");
    });
    
    /** 任務(wù)(^{})在全局隊列(global_queue)中異步執(zhí)行(dispatch_async) */
    dispatch_async(global_queue, ^{
        NSLog(@"執(zhí)行任務(wù)");
    });
    /** 任務(wù)(^{})在全主隊列(main_queue)中異步執(zhí)行(dispatch_async) */
    dispatch_async(main_queue, ^{
        NSLog(@"執(zhí)行任務(wù)");
    });

開發(fā)中常用的一些GCD函數(shù)
1.耗時操作完成回到主線程
dispatch_async(global_queue, ^{
        NSLog(@"執(zhí)行任務(wù)");
      dispatch_async(main_queue, ^{
              NSLog(@"回到主線程刷新UI");
          });
    });  
2.延遲執(zhí)行
  • #define NSEC_PER_SEC 1000000000ull //每秒有多少納秒
  • #define USEC_PER_SEC 1000000ull //每秒有多少毫秒
  • #define NSEC_PER_USEC 1000ull //每毫秒有多少納秒
/**
 延遲執(zhí)行
 _func_ dispatch_time(<#dispatch_time_t when#>, <#int64_t delta#>)
 _func_ dispatch_after(<#dispatch_time_t when#>, <#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
 
 */
- (void)func_dispatch_after{
    // 延遲時間
    double delayInSeconds = 2.0;
    dispatch_time_t time_source = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    
    // 主隊列中延遲執(zhí)行
    dispatch_after(time_source, dispatch_get_main_queue(), ^{
        
    });
}
3.執(zhí)行一次(單例)
/**
 執(zhí)行一次
 _func_ dispatch_once(<#dispatch_once_t * _Nonnull predicate#>, <#^(void)block#>)
 @return
 */
+ (instancetype)func_dispatch_Once{
    static GCDVC *_singleVC = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _singleVC = [GCDVC new];
    });
    return _singleVC;
}
4.隊列組( 可以使用 queue 的隊列組)
  • dispatch_group_create() //創(chuàng)建組
  • dispatch_group_async(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull queue, ^(void)block) //添加任務(wù)到相應(yīng)隊列組
  • dispatch_group_notify(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull queue, ^(void)block) //通知蒂窒,不阻塞線程
  • dispatch_group_wait(dispatch_group_t _Nonnull group, dispatch_time_t timeout) //阻塞線程到隊列任務(wù)執(zhí)行完
/**
 隊列組
 可以使用 queue 的隊列組
 */
- (void)func_dispatch_groups{
    // 組
    dispatch_group_t group = dispatch_group_create();
    // 全局隊列
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_async(group, global_queue, ^{
        NSLog(@"任務(wù) 1");
    });
    
    dispatch_group_async(group, global_queue, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任務(wù) 2");
    });
    
    dispatch_group_async(group, global_queue, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"任務(wù) 3");
    });
    
    /** 判斷 隊列組全部執(zhí)行完成 的兩個方法*/
    
    // dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 阻塞當(dāng)前線程 直到隊列組任務(wù)執(zhí)行完
    
    // 隊列組任務(wù)執(zhí)行完 接到通知 ,不會阻塞線程
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"所有執(zhí)行完成");
    });
    
}

5.隊列組 ( 無法直接使用隊列變量(queue)的 打包組)
  • dispatch_group_enter(dispatch_group_t _Nonnull group)
  • dispatch_group_leave(dispatch_group_t _Nonnull group)
/**
 隊列組
 無法直接使用隊列變量(queue)的 打包組
 */
- (void)func_dispatch_enterAndLeave{
    // URL
    NSString *URLString = [NSString stringWithFormat:@"http://www.baidu.com"];
    NSURL *URL = [[NSURL alloc] initWithString:URLString];
    
    // session
    NSURLSession *sessionManager = [NSURLSession sharedSession];
    sessionManager.configuration.timeoutIntervalForRequest = 20;
    sessionManager.configuration.timeoutIntervalForResource = 20;
    
    // 創(chuàng)建 group
    dispatch_group_t group = dispatch_group_create();
    
    // task
    // 進入group
    dispatch_group_enter(group);
    NSURLSessionTask *task =
    [sessionManager dataTaskWithURL:URL
                  completionHandler:^(NSData * _Nullable data,
                                      NSURLResponse * _Nullable response,
                                      NSError * _Nullable error) {
                      NSLog(@"拿到數(shù)據(jù)");
                      // 離開group
                      dispatch_group_leave(group);
                  }];
    
    // resume
    [task resume];
}

自己創(chuàng)建隊列:使用dispatch_group_async荞怒。
無法直接使用隊列變量(如使用AFNetworking添加異步任務(wù)):使用dispatch_group_enter洒琢,dispatch_group_leave。
使用dispatch_group_enter褐桌,dispatch_group_leave就可以方便的將一系列網(wǎng)絡(luò)請求“打包”起來~
添加結(jié)束任務(wù)
添加結(jié)束任務(wù)也可以分為兩種情況衰抑,如下:
在當(dāng)前線程阻塞的同步等待:dispatch_group_wait。
添加一個異步執(zhí)行的任務(wù)作為結(jié)束任務(wù):dispatch_group_notify

6.快速遍歷
  • dispatch_apply(size_t iterations, dispatch_queue_t _Nonnull queue, ^(size_t)block)
  • dispatch_apply 的作用是在一個隊列上“運行”多次block荧嵌,其實就是簡化了用循環(huán)去向隊列依次添加block任務(wù)
  • dispatch_apply 會開啟線程 快速執(zhí)行完循環(huán)
  • dispatch_apply (阻塞當(dāng)前線程呛踊,直到循環(huán)執(zhí)行完成)
/**
 快速遍歷
 */
- (void)func_dispatch_apply{
    dispatch_queue_t custom_concurrent_queue = dispatch_queue_create("com.boundless.concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_apply(50/** 循環(huán)次數(shù) */, custom_concurrent_queue, ^(size_t i) {
        NSLog(@"%zu",i);
    });
}
7.柵欄砾淌、用于 解決并發(fā)隊列中 讀寫同一個資源搶奪的情況

dispatch_barrier_async(dispatch_queue_t _Nonnull queue, ^(void)block)
dispatch_barrier_sync(dispatch_queue_t _Nonnull queue, ^(void)block)

  • dispatch_barrier_async(異步,不會阻塞當(dāng)前線程) 會設(shè)置柵欄 柵欄之后的任務(wù)會等到柵欄之前的任務(wù)執(zhí)行完成再執(zhí)行
  • dispatch_barrier_async 必須配合 DISPATCH_QUEUE_CONCURRENT( 自定義的并發(fā)隊列),其他隊列 dispatch_barrier_async的作用和 dispatch_async 一樣
  • dispatch_barrier_sync(同步谭网,阻塞當(dāng)前線程 ) 其他和 dispatch_barrier_async 一樣
/**
 柵欄
 用于 解決并發(fā)隊列中 讀寫同一個資源搶奪的情況
 */
- (void)func_dispatch_barrier_async{
    dispatch_queue_t custom_concurrent_queue = dispatch_queue_create("com.boundless.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(custom_concurrent_queue, ^{
        NSLog(@"寫入數(shù)據(jù) 1");
    });
    
    dispatch_async(custom_concurrent_queue,^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"寫入數(shù)據(jù) 2");
    });
    dispatch_barrier_async(custom_concurrent_queue, ^{
        NSLog(@"等待數(shù)據(jù)寫入完畢");
    });
    
    dispatch_async(custom_concurrent_queue, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"讀取數(shù)據(jù) 1");
    });
    
    dispatch_async(custom_concurrent_queue, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"讀取數(shù)據(jù) 2");
    });
    
}
8.隊列掛起/隊列重啟
  • dispatch_suspend(dispatch_object_t _Nonnull object)
  • dispatch_resume(dispatch_object_t _Nonnull object)
  • dispatch_suspend 不能阻止正在執(zhí)行的任務(wù) 只會阻止還未執(zhí)行的任務(wù)
/**
 隊列掛起/隊列重啟
 */
- (void)func_dispatch_suspendAndResume{
    dispatch_queue_t custom_concurrent_queue = dispatch_queue_create("com.boundless.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(custom_concurrent_queue, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"執(zhí)行任務(wù) 1");
    });
    
    dispatch_async(custom_concurrent_queue,^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"執(zhí)行任務(wù) 2");
    });
    
    dispatch_suspend(custom_concurrent_queue);
    [NSThread sleepForTimeInterval:1.0];
    dispatch_resume(custom_concurrent_queue);
}
9.信號量 Dispatch Semaphore保證同步的方法

使用dispatch_semaphore_signal加1 dispatch_semaphore_wait減1汪厨,為0時等待的設(shè)置方式來達到線程同步的目的和同步鎖一樣能夠解決資源搶占的問題。

  • dispatch_semaphore_create(long value)
  • dispatch_semaphore_signal(dispatch_semaphore_t _Nonnull dsema)
  • dispatch_semaphore_wait(dispatch_semaphore_t _Nonnull dsema, dispatch_time_t timeout)
dispatch_semaphore_t signal = dispatch_semaphore_create(1); //傳入值必須 >=0, 若傳入為0則阻塞線程并等待timeout,時間到后會執(zhí)行其后的語句
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);

//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"線程1 等待ing");
    dispatch_semaphore_wait(signal, overTime); //signal 值 -1
    NSLog(@"線程1");
    dispatch_semaphore_signal(signal); //signal 值 +1
    NSLog(@"線程1 發(fā)送信號");
    NSLog(@"--------------------------------------------------------");
});

//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"線程2 等待ing");
    dispatch_semaphore_wait(signal, overTime);
    NSLog(@"線程2");
    dispatch_semaphore_signal(signal);
    NSLog(@"線程2 發(fā)送信號");
});

關(guān)于信號量愉择,我們可以用停車來比喻:

停車場剩余4個車位劫乱,那么即使同時來了四輛車也能停的下。如果此時來了五輛車锥涕,那么就有一輛需要等待衷戈。
信號量的值(signal)就相當(dāng)于剩余車位的數(shù)目,dispatch_semaphore_wait 函數(shù)就相當(dāng)于來了一輛車层坠,dispatch_semaphore_signal 就相當(dāng)于走了一輛車殖妇。停車位的剩余數(shù)目在初始化的時候就已經(jīng)指明了(dispatch_semaphore_create(long value)),調(diào)用一次 dispatch_semaphore_signal窿春,剩余的車位就增加一個拉一;調(diào)用一次dispatch_semaphore_wait 剩余車位就減少一個;當(dāng)剩余車位為 0 時旧乞,再來車(即調(diào)用 dispatch_semaphore_wait)就只能等待蔚润。有可能同時有幾輛車等待一個停車位。有些車主沒有耐心尺栖,給自己設(shè)定了一段等待時間嫡纠,這段時間內(nèi)等不到停車位就走了,如果等到了就開進去停車延赌。而有些車主就像把車停在這除盏,所以就一直等下去。

10.dispatch_queue_set_specific挫以、dispatch_get_specific

FMDB利用它來防止死鎖
作用類似objc_setAssociatedObject跟objc_getAssociatedObject

 static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey;
 //創(chuàng)建串行隊列者蠕,所有數(shù)據(jù)庫的操作都在這個隊列里
 _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
 //標(biāo)記隊列
 dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL);
 
 //檢查是否是同一個隊列來避免死鎖的方法
 - (void)inDatabase:(void (^)(FMDatabase *db))block {
 FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
 assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掐松,隨后出現(xiàn)的幾起案子踱侣,更是在濱河造成了極大的恐慌,老刑警劉巖大磺,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抡句,死亡現(xiàn)場離奇詭異,居然都是意外死亡杠愧,警方通過查閱死者的電腦和手機待榔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來流济,“玉大人锐锣,你說我怎么就攤上這事腌闯。” “怎么了雕憔?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵绑嘹,是天一觀的道長。 經(jīng)常有香客問我橘茉,道長,這世上最難降的妖魔是什么姨丈? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任畅卓,我火速辦了婚禮,結(jié)果婚禮上蟋恬,老公的妹妹穿的比我還像新娘翁潘。我一直安慰自己,他們只是感情好歼争,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布拜马。 她就那樣靜靜地躺著,像睡著了一般沐绒。 火紅的嫁衣襯著肌膚如雪俩莽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天乔遮,我揣著相機與錄音扮超,去河邊找鬼。 笑死蹋肮,一個胖子當(dāng)著我的面吹牛出刷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坯辩,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼馁龟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漆魔?” 一聲冷哼從身側(cè)響起坷檩,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎有送,沒想到半個月后淌喻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡雀摘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年裸删,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阵赠。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡涯塔,死狀恐怖肌稻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匕荸,我是刑警寧澤爹谭,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站榛搔,受9級特大地震影響诺凡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜践惑,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一腹泌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尔觉,春花似錦凉袱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钉稍,卻和暖如春涤躲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贡未。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工篓叶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羞秤。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓缸托,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘾蛋。 傳聞我的和親對象是個殘疾皇子俐镐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

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