GCD總結(jié)筆記

章節(jié)目錄

  • 什么是GCD感猛?
  • 如何在多條路徑中執(zhí)行CPU命令列唱遭?
  • 即使多線程存在很多問題(如數(shù)據(jù)競爭拷泽、死鎖、線程過多消耗大量內(nèi)存)拆吆,為何還要使用多線程枣耀?
  • Dispatch Queue
  • dispatch_set_target_queue
  • dispatch_after
  • dispatch_time
  • dispatch_walltime
  • Dispatch Group
  • dispatch_group_wait
  • dispatch_barrier_async
  • dispatch_sync 與 dispatch_async
  • dispatch_apply
  • dispatch_suspend / dispatch_resume
  • Dispatch Semaphore
  • dispatch_once
  • Dispatch I/0
  • GCD實現(xiàn)
  • 參考資料

正文:

  • 什么是GCD捞奕?

GCD是異步執(zhí)行任務(wù)的技術(shù)之一颅围。
一般應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)中實現(xiàn)恨搓。
所以我們只需定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中斧抱,GCD就能生成必要的線程并計劃執(zhí)行任務(wù)辉浦。

在導(dǎo)入GCD之前,Cocoa框架提供了NSThread等簡單的多線程編程技術(shù)眉睹,但通過源碼對比可知GCD更為簡潔竹海,執(zhí)行效率也更高丐黄。

一個CPU一次只能執(zhí)行一個命令,不能執(zhí)行某處分開的并列的兩個命令坏瞄,因此通過CPU執(zhí)行的CPU命令列就好比一條無分叉的大道鸠匀,其執(zhí)行不會出現(xiàn)分歧逾柿。
而在OC的if等控制語句或函數(shù)調(diào)用的情況下机错,執(zhí)行命令列的地址會遠離當(dāng)前的位置(位置遷移)

一個CPU執(zhí)行的CPU命令列為一條無分叉路徑弱匪,即為線程萧诫。
多線程即為多條路徑。多線程中哑诊,1個CPU核執(zhí)行多條不同路徑上的不同命令。
一個64核的CPU芯片有64個CPU提茁。


CPU命令列.png
  • 一個CPU核一次能夠執(zhí)行的CPU命令始終為1茴扁,那如何在多條路徑中執(zhí)行CPU命令列汪疮?

OSX和iOS的核心XNU內(nèi)核在發(fā)生操作系統(tǒng)事件時會切換執(zhí)行路徑(如每隔一定時間智嚷,喚起系統(tǒng)調(diào)用等情況)盏道。
執(zhí)行中路徑的狀態(tài),如CPU的寄存器等信息保存到各自路徑專用的內(nèi)存塊中嫁艇,從切換目標路徑專用的內(nèi)存塊中弦撩,復(fù)原CPU寄存器等信息益楼,繼續(xù)執(zhí)行切換路徑的CPU命令列偏形。這被稱為”上下文切換”。

由于使用多線程的程序可以在某個線程和其他線程之間反復(fù)多次進行上下文切換队橙,因此看上去就好像一個CPU核能夠并列地執(zhí)行多個線程一樣捐康。

但具有多個CPU核時解总,就不是看上去像了花枫,而是真的多個CPU核并行執(zhí)行多個線程的技術(shù)掏膏。

這種利用多線程編程的技術(shù)就被稱為多線程編程馒疹。

  • 即使多線程存在很多問題(如數(shù)據(jù)競爭颖变、死鎖腥刹、線程過多消耗大量內(nèi)存),為何還要使用多線程漓雅?

多線程編程可保證應(yīng)用程序的響應(yīng)性能邻吞。
主線程是應(yīng)用程序啟動時最先執(zhí)行的線程抱冷,負責(zé)描繪用戶界面旺遮、處理觸摸屏幕的事件等。
若在主線程進行長時間的處理边翼,就會妨礙主線程的執(zhí)行组底,從而導(dǎo)致不能應(yīng)用程序的畫面沒有更新而長時間停滯等問題债鸡。

Dispatch Queue : 執(zhí)行處理的等待隊列厌均。根據(jù)FIFO執(zhí)行操作的處理告唆。
在執(zhí)行處理時存在兩種Dispatch Queue擒悬,一種是等待現(xiàn)在執(zhí)行中的處理的Serial Dispatch Queue(同步)茄螃,另一種是不等待現(xiàn)在執(zhí)行中處理的Concurrent Dispatch Queue(異步)归苍。

Dispatch Queue種類.png


并行執(zhí)行拼弃,使用多個線程同時執(zhí)行多個處理吻氧。
但是并行執(zhí)行的處理數(shù)量取決于當(dāng)前系統(tǒng)的狀態(tài)(Concurrent Dispatch Queue)盯孙。
iOS和OS X的核心 —— XNU內(nèi)核決定應(yīng)當(dāng)使用的線程數(shù)振惰,并只生成所需的線程執(zhí)行處理骑晶。
當(dāng)處理結(jié)束,應(yīng)當(dāng)執(zhí)行的處理數(shù)減少時匙头,XNU內(nèi)核會結(jié)束不再需要的線程(中間會有個放入線程緩存池的操作)蹂析。

  • 如何才能得到Dispatch Queue识窿?

兩種方法喻频。

第一種

通過CGD的API: dispatch_queue_create函數(shù)生成Dispatch Queue
一個Serial Dispatch Queue 同時只能執(zhí)行一個追加處理甥温,但使用 dispatch_queue_create函數(shù)可生成任意多個Dispatch Queue姻蚓。

當(dāng)生成多個Serial Dispatch Queue時狰挡,各個Serial Dispatch Queue將并行執(zhí)行释涛。雖然一個隊列只能生成一個處理唇撬,但可以有多個隊列同時進行一個處理窖认,即為同時執(zhí)行多個處理。
但不可生成太多燕偶,否則會消耗大量內(nèi)存杭跪,引起大量的上下文切換涧尿,大幅降低系統(tǒng)的響應(yīng)性能姑廉。

dispatch_queue_create函數(shù)桥言,第一個參數(shù)指定Serial Dispatch Queue的名稱号阿。
第二個參數(shù)若為NULL則生成的是Serial Dispatch Queue鸳粉,若為DISPATCH_QUEUE_CONCURRENT則生成的是Concurrent Dispatch Queue届谈。

生成的Dispatch Queue必須由程序員負責(zé)釋放艰山,通過dispatch_release(隊列名)釋放曙搬∽葑埃可
通過dispatch_retain(隊列名)增加引用搂擦。
即Dispatch Queue也像OC的引用計數(shù)式內(nèi)存管理一樣瀑踢,需通過dispatch_retain函數(shù)和dispatch_release函數(shù)的引用計數(shù)來管理內(nèi)存橱夭。

GCD的使用.png

如圖所示棘劣,在dispatch_async函數(shù)中追加Block到Concurrent Dispatch Queue首昔,并立即通過dispatch_release函數(shù)進行釋放勒奇。則該Block通過dispatch_retain函數(shù)持有Dispatch Queue赊颠。無論Serial Dispatch Queue還是Concurrent Dispatch Queue都一樣劈彪。

于是在dispatch_async函數(shù)中追加Block到Dispatch Queue后竣蹦,即使立即釋放Dispatch Queue,該Dispatch Queue由于被Block所持有也不會被廢棄沧奴,因而Block能夠執(zhí)行痘括。Block執(zhí)行結(jié)束后會釋放Dispatch Queue,此時誰都不持有Dispatch Queue滔吠,它也因此會被廢棄远寸。

第二種

獲取系統(tǒng)標準提供的Dispatch Queue(Main Dispatch Queue 和 Global Dispatch Queue)

Main Dispatch Queue是在主線程中執(zhí)行的Dispatch Queue。因主線程只有一個屠凶,所以其自然是Serial Dispatch Queue。
追加到Main Dispatch Queue的處理在主線程的RunLoop中執(zhí)行矗愧。所以將用戶界面的界面更新等一些必須在主線程中執(zhí)行的處理追加到Main Dispatch Queue使用灶芝。

Global Dispatch Queue 是所有應(yīng)用程序都能夠使用的Concurrent Dispatch Queue。
其有四個執(zhí)行優(yōu)先級唉韭,分別是高夜涕、默認、低属愤、后臺女器。
通過XNU內(nèi)核管理的用于Global Dispatch Queue的線程,將各自使用的Global Dispatch Queue的執(zhí)行優(yōu)先級作為線程的優(yōu)先級使用住诸。
所以在使用時驾胆,應(yīng)注意優(yōu)先級的選擇涣澡,但通過XNU內(nèi)核用于Global Dispatch Queue的線程并不能保證實時性,因此執(zhí)行優(yōu)先級只是大致的判斷丧诺。
列如在處理內(nèi)容的執(zhí)行可有可無時入桂,使用后臺優(yōu)先級的這種。

后臺優(yōu)先級.png
Main Dispatch Queue的獲炔笛帧:
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

Global Dispatch Queue(高優(yōu)先級)的獲取方法
dispatch queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HEIGH,0);

Global Dispatch Queue(默認優(yōu)先級)的獲取方法
dispatch queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

Global Dispatch Queue(低優(yōu)先級)的獲取方法
dispatch queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_Low,0);

Global Dispatch Queue(后臺優(yōu)先級)的獲取方法
dispatch queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);

對Main Dispatch Queue 和 Global Dispatch Queue執(zhí)行dispatch_retain 和 dispatch_release函數(shù)不會引起任何變化抗愁,也不會有任何問題。
這也是使用其會更輕松的原因呵晚。

dispatch_get_global_queue的第二個參數(shù)蜘腌,官方解釋為留待未來使用,非0就可能返回NULL

  • dispatch_set_target_queue

dispatch_queue_create函數(shù)生成的Dispatch Queue 不管是Serial Dispatch Queue 還是 Concurrent Dispatch Queue饵隙,其使用的線程優(yōu)先級都與Global Dispatch Queue的優(yōu)先級相同逢捺。而變更優(yōu)先級就使用dispatch_set_target_queue函數(shù)。

代碼演示:
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create(“DrunkenMouse”,NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);

第一個參數(shù)的Dispatch Queue的優(yōu)先級會修改為與第二個Dispatch Queue的優(yōu)先級相同癞季。
但第一個參數(shù)若為Main Dispatch Queue 和 Global Dispatch Queue則不知道會出現(xiàn)什么狀況劫瞳,所以不可指定。

  • dispatch_after

指定多少時間后追加操作到Dispatch Queue绷柒,而不是指定時間后執(zhí)行處理志于。

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,3ull * NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(),^{
    NSLog(@“wait at least 3 seconds”);
});

此源碼意為3秒后追加Block操作到Main Dispatch Queue。

  • dispatch_time

dispatch_time函數(shù)獲取從第一個參數(shù)指定的時間開始到第二個參數(shù)指定的毫微妙單位時間后的時間废睦。
第一個參數(shù)是指定時間用的dispatch_time_t類型的值伺绽,使用dispatch_time函數(shù)或dispatch_walltime函數(shù)生成
第二個參數(shù)中ull * NSEC_PER_SEC代表秒,使用NSEC_PER_MSEC代表毫秒
如150毫秒:150ull * NSEC_PER_MESC
ull是C語言的數(shù)值字面量嗜湃,表示unsigned long long

  • dispatch_walltime

dispatch_walltime函數(shù)用于計算絕對時間奈应。比如想指定在X年X月X日X時X分X秒這一絕對時間。

  • Dispatch Group

用于將多個Dispatch Queue 添加到同一個Dispatch Group, 待Dispatch Queue全部執(zhí)行完畢后執(zhí)行某項操作购披。(Serial Dispatch Queue或 Concurrent Dispatch Queue皆可)

dispatch_group_t group = dispatch_group_create(); 生成group
dispatch_group_async(group, queue, ^{NSLog(@“DrunkenMouse”)杖挣;}); 將操作添加到隊列queue刚陡,將隊列queue添加到組group中
dispatch_group_async(group, queue, ^{NSLog(@“DrunkenMouse2”)惩妇;}); 組中可添加多個queue
dispatch_group_notify(group,dispatch_get_main_queue(),^{NSLog(@“done”);}); 通過notify監(jiān)聽group筐乳,在group中所有操作執(zhí)行完畢后歌殃,將第三個參數(shù)的Block添加到第二個參數(shù)的Dispatch Queue。
dispatch_release(group);釋放組

dispatch_group_create函數(shù)生成dispatch_group_t類型的Dispatch Group蝙云。
該Dispatch Group與Dispatch Queue相同氓皱,在使用結(jié)束后通過dispatch_release函數(shù)釋放。
dispatch_group_async函數(shù)將Block追加到指定的Dispatch Queue,Block屬于指定的Dispatch Group波材。
所以Block通過dispatch_retain函數(shù)持有Dispatch Group股淡,于是Block執(zhí)行結(jié)束,該Block就通過dispatch_release函數(shù)釋放持有的Dispatch Group各聘。
一旦Dispatch Group使用結(jié)束,不用考慮Block抡医,立即通過Dispatch_release函數(shù)釋放即可躲因。

  • dispatch_group_wait

在Dispatch Group中使用dispatch_group_wait函數(shù)僅等待全部處理執(zhí)行結(jié)束。
dispatch_group_t group = dispatch_group_create(); 生成group
dispatch_group_async(group, queue, ^{NSLog(@“DrunkenMouse”)忌傻;})大脉; 將操作添加到隊列queue,將隊列queue添加到組group中
dispatch_group_async(group, queue, ^{NSLog(@“DrunkenMouse2”)水孩;})镰矿; 組中可添加多個queue
dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
第二個參數(shù)為等待的時間,屬于dispatch_time_t類型的值俘种。DISPATCH_TIME_FOREVER意味永久等待秤标,只要group中的處理尚未結(jié)束就一直等待。
等待的時間也可以為1秒

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,1ull * NSEC_PER_SEC);
long result = dispatch_group_wait(group,time);
if(result == 0) {
    //屬于Dispatch Group的全部處理執(zhí)行結(jié)束
}else {
    //屬于Dispatch Group的某一個處理還在執(zhí)行中
}

等待意味著一旦調(diào)用dispatch_group_wait函數(shù)宙刘,該函數(shù)就處于調(diào)用的狀態(tài)而不返回苍姜。
在經(jīng)過指定時間或Dispatch Group的處理全部執(zhí)行結(jié)束之前,執(zhí)行該函數(shù)的線程停止悬包。
若不等待則可以使用DISPATCH_TIME_NOW:

long result = dispatch_group_wait(group,DISPATCH_TIME_NOW);
  • dispatch_barrier_async

dispatch_barrier_async 柵欄衙猪,可保證寫入時不會讀取,讀取時不會寫入布近。
進而可將寫入操作放到Serial Dispatch Queue中垫释,讀取操作放入Serial Dispatch Queue,以提高性能撑瞧。

dispatch_async(queue,blk1_reading);
dispatch_async(queue,blk2_reading);
dispatch_barrier_async(queue,blk3_writing);
dispatch_async(queue,blk4_reading);

dispatch_barrier_async函數(shù)會等到目前為止的并行都處理結(jié)束后棵譬,再去執(zhí)行此操作,而在執(zhí)行該寫入操作時禁止再執(zhí)行別的操作预伺。

  • dispatch_sync 與 dispatch_async

dispatch_async 異步茫船,將指定的Block”非同步”的追加到指定的Dispatch Queue,dispatch_async函數(shù)不做任何等待扭屁。
dispatch_sync 同步算谈,將指定的Block”同步”追加到指定的Dispatch Queue中,在追加Block結(jié)束之前料滥,dispatch_sync函數(shù)會一直等待然眼。
等待的意思同dispatch_group_wait,該線程直到處理結(jié)束才會返回葵腹。
同步主隊列操作會導(dǎo)致死鎖高每。也就是dispatch_sync(dispatch_get_main_queue(),blk1);
死鎖原因:Main Dispatch Queue會等待主線程中操作執(zhí)行執(zhí)行完畢再執(zhí)行該操作屿岂。于是主線程等待該操作結(jié)束才繼續(xù)執(zhí)行,該操作又在等待主線程操作結(jié)束才能執(zhí)行鲸匿。

同一個隊列爷怀,異步操作里嵌套同步操作會發(fā)生Crash。(XCode8 測試)

  • dispatch_apply

該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中带欢,并等待全部處理執(zhí)行結(jié)束运授。
第二個參數(shù)為重復(fù)次數(shù),第二個參數(shù)為添加到的隊列乔煞,第三個參數(shù)為追加的處理

dispatch_apply(10,queue,blk1);
NSLog(@“DrunkenMouse”);

blk1添加10此到隊列queue吁朦,待操作全都執(zhí)行完畢后輸出DrunkenMouse
第三個參數(shù)Block為帶有參數(shù)的Block,這是為了區(qū)分添加的Block所用渡贾。
由于dispatch_apply函數(shù)與dispatch_sync函數(shù)相同逗宜,會等待處理執(zhí)行結(jié)束。
因此推薦在dispatch_async函數(shù)非同步的執(zhí)行dispatch_apply函數(shù)空骚。

  • dispatch_suspend / dispatch_resume

dispatch_suspend(queue)將指定的Dispatch Queue掛起纺讲。
即不執(zhí)行追加到該Dispatch Queue中未執(zhí)行的處理,但已經(jīng)執(zhí)行的處理不受影響囤屹。
dispatch_resume(queue)恢復(fù)指定的Dispatch Queue

  • Dispatch Semaphore

數(shù)據(jù)信號燈刻诊。當(dāng)計數(shù)為0時等待,計數(shù)為1或大于1時牺丙,減去1而不等待则涯。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
參數(shù)表示計數(shù)的初始值,由create可看出冲簿,同樣需dispatch_release函數(shù)釋放粟判。可通過dispatch_retain函數(shù)持有峦剔。
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
該函數(shù)等待Dispatch Semaphore的計數(shù)值大于或等于1档礁。當(dāng)滿足時計數(shù)減一并從dispatch_semaphore_wait函數(shù)返回。
返回0代表計數(shù)值大于或等于1吝沫,計數(shù)減一呻澜。否則就是沒返回值。
第二個參數(shù)與dispatch_group_wait函數(shù)等相同惨险,由dispatch_time_t類型值指定等待時間羹幸。
計數(shù)值的加1通過dispatch_semaphore_signal函數(shù)

  • dispatch_once

一次執(zhí)行。在程序運行階段辫愉,其函數(shù)只會執(zhí)行一次栅受。

  • Dispatch I/0

在讀取較大文件時,可將文件分成合適的大小并使用Global Dispatch Queue并列讀取來提升速度。實現(xiàn)這一功能的就是Dispatch I/O 和 Dispatch Data

  • GCD實現(xiàn)

編程人員所使用GCD的API全部為包含在libdispatch 庫中的C語言函數(shù)屏镊。
Dispatch Queue通過結(jié)構(gòu)體和鏈表依疼,被實現(xiàn)為FIFO隊列。
FIFO隊列管理是通過dispatch_async等函數(shù)所追加的Block而芥。
Block并不是直接加入FIFO隊列律罢,而是先加入Dispatch Continuation這一dispatch_continuation_t類型結(jié)構(gòu)體中,然后再加入FIFO隊列棍丐。
該DispatchContinuation用于記憶Block所屬的DispatchGroup和其他一些信息误辑,相當(dāng)于一般常說的執(zhí)行上下文。

Global Dispatch Queue有8種:
HighPriority DefaultPriority LowPriority BackgroundPriority
HighOvercommitPriority DefaultOvercommitPriority LowOvercommitPriority BackgroundOvercommitPriority
優(yōu)先級中附有Overcommit的Global Dispatch Queue使用在SerialDispatchQueue中骄酗。
如Overcommit這個名稱所示稀余,不管系統(tǒng)狀態(tài)如何悦冀,都會強制生成線程的DispatchQueue
這八種Global Dispatch Queue各使用一個pthread_workqueue.
GCD初始化時趋翻,使用pthread_workqueue_create_np函數(shù)生成pthread_workqueue.
pthread_workqueue包含在Libc提供的Pthreads API中。其使用bsdthread_register和workq_open系統(tǒng)調(diào)用盒蟆,在初始化XNU內(nèi)核的work queue之后獲取workqueue信息
XNU內(nèi)核持有4種work queue
WORKQUEUE_HIGH_PRIOQUEUE
WORKQUEUE_DEFAULT_PRIOQUEUE
WORKQUEUE_LOW_PRIOQUEUE
WORKQUEUE_BG_PRIOQUEUE

Dispatch Queue中執(zhí)行Block的過程踏烙。當(dāng)在Global Dispatch Queue 中執(zhí)行Block時,libdispatch從Global Dispatch Queue自身的FIFO隊列中取出Dispatch Continuation历等,調(diào)用pthread_workqueue_additem_np函數(shù)讨惩。將該Global Dispatch Queue自身、符合其優(yōu)先級的work queue信息以及為執(zhí)行Dispatch Continuation的回調(diào)函數(shù)等傳遞給參數(shù)寒屯。

看圖.png


pthread_workqueue_additem_np函數(shù)使用workq_kernreturn系統(tǒng)調(diào)用荐捻,通知work queue增加應(yīng)當(dāng)執(zhí)行的項目。根據(jù)該通知寡夹,XNU內(nèi)核基于系統(tǒng)狀態(tài)判斷是否要生成線程处面,如果是Overcommit優(yōu)先級的Global Dispatch Queue,workqueue則始終生成線程菩掏。
work queue的線程執(zhí)行pthread_workqueue函數(shù)魂角,該函數(shù)調(diào)用libdispatch的回調(diào)函數(shù)。在該回調(diào)函數(shù)中執(zhí)行加入到DispatchContinuation的Block
Block執(zhí)行結(jié)束后智绸,進行通知DispatchGroup結(jié)束野揪、釋放DispatchContinuation等處理,開始準備執(zhí)行加入到GlobalDispatchQueue中的下一個Block瞧栗。

  • 參考
  • Objective-C高級編程:iOS與OS X多線程和內(nèi)存管理
  • 簡書博客
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斯稳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子迹恐,更是在濱河造成了極大的恐慌平挑,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異通熄,居然都是意外死亡唆涝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門唇辨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廊酣,“玉大人,你說我怎么就攤上這事赏枚⊥龀郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵饿幅,是天一觀的道長凡辱。 經(jīng)常有香客問我,道長栗恩,這世上最難降的妖魔是什么透乾? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮磕秤,結(jié)果婚禮上乳乌,老公的妹妹穿的比我還像新娘。我一直安慰自己市咆,他們只是感情好汉操,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蒙兰,像睡著了一般磷瘤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搜变,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天采缚,我揣著相機與錄音,去河邊找鬼痹雅。 笑死仰担,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绩社。 我是一名探鬼主播摔蓝,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼愉耙!你這毒婦竟也來了贮尉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朴沿,失蹤者是張志新(化名)和其女友劉穎猜谚,沒想到半個月后败砂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡魏铅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年昌犹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片览芳。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡斜姥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沧竟,到底是詐尸還是另有隱情铸敏,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布悟泵,位于F島的核電站杈笔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏糕非。R本人自食惡果不足惜蒙具,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峰弹。 院中可真熱鬧店量,春花似錦芜果、人聲如沸鞠呈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚁吝。三九已至,卻和暖如春舀射,著一層夾襖步出監(jiān)牢的瞬間窘茁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工脆烟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留山林,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓邢羔,卻偏偏與公主長得像驼抹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拜鹤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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