Linux多線程編程講解之系列二

多線程系列文章源碼頭文件內(nèi)容:

#include<pthread.h>

#include<stdio.h>

#include<unistd.h>

作為程序員徘铝,就是要減少重復(fù)勞動(dòng)衍锚,拒絕一切無目的的DIY晴及。哪怕只有三行代碼虚倒,哈哈??

在上一篇文章中诊笤,我們談到了會(huì)導(dǎo)致異常結(jié)果的線程代碼系谐。兩個(gè)線程分別對(duì)同一個(gè)全局變量進(jìn)行了二十次加一。變量的值最后應(yīng)該是 40讨跟,但最終值卻是 21纪他。這是怎么回事呢?因?yàn)橐粋€(gè)線程不停地“取消”了另一個(gè)線程執(zhí)行的加一操作晾匠,所以產(chǎn)生這個(gè)問題〔杼唬現(xiàn)在讓我們來查看改正后的代碼,它使用?互斥對(duì)象(mutex)來解決該問題:

int?myglobal;??

pthread_mutex_t?mymutex=PTHREAD_MUTEX_INITIALIZER;??

void?*thread_function(void?*arg)?{??

int?i,j;??

for?(?i=0;?i<20;?i++)?{??

????pthread_mutex_lock(&mymutex);??

????j=myglobal;??

????j=j+1;??

printf(".");??

????fflush(stdout);??

????sleep(1);??

????myglobal=j;??

????pthread_mutex_unlock(&mymutex);??

??}??

return?NULL;??

}??

int?main(void)?{??

??pthread_t?mythread;??

int?i;??

if?(?pthread_create(?&mythread,?NULL,?thread_function,?NULL)?)?{??

printf("error?creating?thread.");??

????abort();??

??}??

for?(?i=0;?i<20;?i++)?{??

????pthread_mutex_lock(&mymutex);??

????myglobal=myglobal+1;??

????pthread_mutex_unlock(&mymutex);??

printf("o");??

????fflush(stdout);??

????sleep(1);??

??}??

if?(?pthread_join?(?mythread,?NULL?)?)?{??

printf("error?joining?thread.");??

????abort();??

??}??

printf("\nmyglobal?equals?%d\n",myglobal);??

??exit(0);??

}??

解讀一哈哈哈

如果將這段代碼與系列一的中給出的版本作一個(gè)比較凉馆,就會(huì)注意到增加了 pthread_mutex_lock() 和 pthread_mutex_unlock() 函數(shù)調(diào)用薪寓。在線程程序中這些調(diào)用執(zhí)行了不可或缺的功能。他們提供了一種相互排斥的方法(互斥對(duì)象即由此得名)澜共。兩個(gè)線程不能同時(shí)對(duì)同一個(gè)互斥對(duì)象加鎖向叉。

互斥對(duì)象是這樣工作的。如果線程 a 試圖鎖定一個(gè)互斥對(duì)象嗦董,而此時(shí)線程 b 已鎖定了同一個(gè)互斥對(duì)象時(shí)母谎,線程 a 就將進(jìn)入睡眠狀態(tài)。一旦線程 b 釋放了互斥對(duì)象(通過 pthread_mutex_unlock() 調(diào)用)京革,線程 a 就能夠鎖定這個(gè)互斥對(duì)象(換句話說奇唤,線程 a 就將從 pthread_mutex_lock() 函數(shù)調(diào)用中返回幸斥,同時(shí)互斥對(duì)象被鎖定)。同樣地咬扇,當(dāng)線程 a 正鎖定互斥對(duì)象時(shí)甲葬,如果線程 c 試圖鎖定互斥對(duì)象的話,線程 c 也將臨時(shí)進(jìn)入睡眠狀態(tài)冗栗。對(duì)已鎖定的互斥對(duì)象上調(diào)用 pthread_mutex_lock() 的所有線程都將進(jìn)入睡眠狀態(tài)演顾,這些睡眠的線程將“排隊(duì)”訪問這個(gè)互斥對(duì)象。

通常使用 pthread_mutex_lock() 和 pthread_mutex_unlock() 來保護(hù)數(shù)據(jù)結(jié)構(gòu)隅居。這就是說钠至,通過線程的鎖定和解鎖,對(duì)于某一數(shù)據(jù)結(jié)構(gòu)胎源,確保某一時(shí)刻只能有一個(gè)線程能夠訪問它(思考:這樣算是把并發(fā)搞成“同步”了嗎棉钧?整體并發(fā)能力和單線程有提升嗎?)涕蚤∠芮洌可以推測到,當(dāng)線程試圖鎖定一個(gè)未加鎖的互斥對(duì)象時(shí)万栅,POSIX 線程庫將同意鎖定佑钾,而不會(huì)使線程進(jìn)入睡眠狀態(tài)。

鎖定了互斥對(duì)象的線程能夠存取復(fù)雜的數(shù)據(jù)結(jié)構(gòu)烦粒,而不必?fù)?dān)心同時(shí)會(huì)有其它線程干擾休溶。那個(gè)數(shù)據(jù)結(jié)構(gòu)實(shí)際上是“凍結(jié)”了,直到互斥對(duì)象被解鎖為止扰她。pthread_mutex_lock() 和 pthread_mutex_unlock() 函數(shù)調(diào)用兽掰,如同“在施工中”標(biāo)志一樣,將正在修改和讀取的某一特定共享數(shù)據(jù)包圍起來徒役。這兩個(gè)函數(shù)調(diào)用的作用就是警告其它線程孽尽,要它們繼續(xù)睡眠并等待輪到它們對(duì)互斥對(duì)象加鎖。當(dāng)然忧勿,除非在?每個(gè)?對(duì)特定數(shù)據(jù)結(jié)構(gòu)進(jìn)行讀寫操作的語句前后杉女,都分別放上 pthread_mutex_lock() 和 pthread_mutext_unlock() 調(diào)用,才會(huì)出現(xiàn)這種情況鸳吸。

為什么要用互斥對(duì)象熏挎?

聽上去很有趣,但究竟為什么要讓線程睡眠呢层释?要知道婆瓜,線程的主要優(yōu)點(diǎn)不就是其具有獨(dú)立工作、更多的時(shí)候是同時(shí)工作的能力嗎?是的廉白,確實(shí)是這樣个初。然而,每個(gè)重要的線程程序都需要使用某些互斥對(duì)象猴蹂。讓我們再看一下示例程序以便理解原因所在院溺。

請(qǐng)看 thread_function(),循環(huán)中一開始就鎖定了互斥對(duì)象磅轻,最后才將它解鎖珍逸。在這個(gè)示例程序中,mymutex 用來保護(hù) myglobal 的值聋溜。仔細(xì)查看 thread_function()谆膳,加一代碼把 myglobal 復(fù)制到一個(gè)局部變量,對(duì)局部變量加一撮躁,睡眠一秒鐘漱病,在這之后才把局部變量的值傳回給 myglobal。不使用互斥對(duì)象時(shí)把曼,即使主線程在 thread_function() 線程睡眠一秒鐘期間內(nèi)對(duì) myglobal 加一杨帽,thread_function() 蘇醒后也會(huì)覆蓋主線程所加的值。使用互斥對(duì)象能夠保證這種情形不會(huì)發(fā)生嗤军。(您也許會(huì)想到注盈,我增加了一秒鐘延遲以觸發(fā)不正確的結(jié)果。把局部變量的值賦給 myglobal 之前叙赚,實(shí)際上沒有什么真正理由要求 thread_function() 睡眠一秒鐘老客。)使用互斥對(duì)象的新程序產(chǎn)生了期望的結(jié)果:

$ ./thread3

o..o..o.o..o..o.o.o.o.o..o..o..o.ooooooo

myglobal equals 40

注:你的運(yùn)行結(jié)果和我這會(huì)不一樣哦,不要驚奇纠俭,這就是多線程的魅力沿量。老衲后面給出解釋~

為了進(jìn)一步探索這個(gè)極為重要的概念浪慌,讓我們看一看程序中進(jìn)行加一操作的代碼:

thread_function()?加一代碼:??

????j=myglobal;??

????j=j+1;??

printf(".");??

????fflush(stdout);??

????sleep(1);??

????myglobal=j;??

主線程加一代碼:??

????myglobal=myglobal+1;

如果代碼是位于單線程程序中冤荆,可以預(yù)期 thread_function() 代碼將完整執(zhí)行。

接下來才會(huì)執(zhí)行主線程代碼(或者是以相反的順序執(zhí)行)权纤。在不使用互斥對(duì)象的線程程

序中钓简,代碼可能(幾乎是,由于調(diào)用了 sleep() 的緣故)以如下的順序執(zhí)行:

thread_function()?線程????????主線程??

j=myglobal;??

j=j+1;??

printf(".");??

fflush(stdout);??

sleep(1);?????????????????????myglobal=myglobal+1;??

myglobal=j;??

當(dāng)代碼以此特定順序執(zhí)行時(shí)汹想,將覆蓋主線程對(duì) myglobal 的修改外邓。程序結(jié)束后,就將得到

不正確的值古掏。如果是在操縱指針的話损话,就可能產(chǎn)生段錯(cuò)誤。注意到 thread_function()線程按順序執(zhí)行了它的所有指令∩デ梗看來不象是 thread_function() 有什么次序顛倒光涂。

問題是,同一時(shí)間內(nèi)拧烦,另一個(gè)線程對(duì)同一數(shù)據(jù)結(jié)構(gòu)進(jìn)行了另一個(gè)修改忘闻。

線程內(nèi)幕 1

在解釋如何確定在何處使用互斥對(duì)象之前,先來深入了解一下線程的內(nèi)部工作機(jī)制恋博。

請(qǐng)看第一個(gè)例子:

假設(shè)主線程將創(chuàng)建三個(gè)新線程:線程 a齐佳、線程 b 和線程 c。假定首先創(chuàng)建線程 a债沮,

然后是線程 b炼吴,最后創(chuàng)建線程 c。

pthread_create(?&thread_a,?NULL,?thread_function,?NULL);??

pthread_create(?&thread_b,?NULL,?thread_function,?NULL);??

pthread_create(?&thread_c,?NULL,?thread_function,?NULL);

在第一個(gè) pthread_create() 調(diào)用完成后疫衩,可以假定線程 a 不是已存在就是已結(jié)束并停止缺厉。

第二個(gè) pthread_create() 調(diào)用后,主線程和線程 b 都可以假定線程 a 存在(或已停止)隧土。

然而提针,就在第二個(gè) create() 調(diào)用返回后,主線程無法假定是哪一個(gè)線程(a 或 b)會(huì)首先開始運(yùn)行曹傀。雖然兩個(gè)線程都已存在辐脖,線程 CPU 時(shí)間片的分配取決于內(nèi)核和線程庫。至于誰將首先運(yùn)行皆愉,并沒有嚴(yán)格的規(guī)則嗜价。盡管線程 a 更有可能在線程 b 之前開始執(zhí)行,但這并無保證幕庐。對(duì)于多處理器系統(tǒng)久锥,情況更是如此。如果編寫的代碼假定在線程 b 開始執(zhí)行之前實(shí)際上執(zhí)行線程 a 的代碼异剥,那么瑟由,程序最終正確運(yùn)行的概率是 99%≡┦伲或者更糟糕歹苦,程序在您的機(jī)器上 100% 地正確運(yùn)行,而在您客戶的四處理器服務(wù)器上正確運(yùn)行的概率卻是零督怜。

從這個(gè)例子還可以得知殴瘦,線程庫保留了每個(gè)單獨(dú)線程的代碼執(zhí)行順序。換句話說号杠,

實(shí)際上那三個(gè) pthread_create() 調(diào)用將按它們出現(xiàn)的順序執(zhí)行蚪腋。從主線程上來看丰歌,所有代碼都是依次執(zhí)行的。有時(shí)屉凯,可以利用這一點(diǎn)來優(yōu)化部分線程程序动遭。

例如,在上例中神得,線程 c 就可以假定線程 a 和線程 b 不是正在運(yùn)行就是已經(jīng)終止厘惦。它不必?fù)?dān)心存在還沒有創(chuàng)建線程 a 和線程 b 的可能性×ú荆可以使用這一邏輯來優(yōu)化線程程序宵蕉。

線程內(nèi)幕 2

現(xiàn)在來看另一個(gè)假想的例子。假設(shè)有許多線程节榜,他們都正在執(zhí)行下列代碼:

myglobal=myglobal+1;

那么羡玛,是否需要在加一操作語句前后分別鎖定和解鎖互斥對(duì)象呢?也許有人會(huì)說“不”宗苍。編譯器極有可能把上述賦值語句編譯成一條機(jī)器指令稼稿。大家都知道,不可能"半途"中斷一條機(jī)器指令讳窟。即使是硬件中斷也不會(huì)破壞機(jī)器指令的完整性让歼。基于以上考慮丽啡,很可能傾向于完全省略pthread_mutex_lock() 和 pthread_mutex_unlock() 調(diào)用谋右。

不要這樣做。我在說廢話嗎补箍?不完全是這樣改执。首先,不應(yīng)該假定上述賦值語句一定會(huì)被編譯成一條機(jī)器指令坑雅,除非親自驗(yàn)證了機(jī)器代碼辈挂。即使插入某些內(nèi)嵌匯編語句以確保加一操作的完整執(zhí)行――甚至,即使是自己動(dòng)手寫編譯器裹粤!-- 仍然可能有問題终蒂。答案在這里。使用單條內(nèi)嵌匯編操作碼在單處理器系統(tǒng)上可能不會(huì)有什么問題蛹尝。

每個(gè)加一操作都將完整地進(jìn)行后豫,并且多半會(huì)得到期望的結(jié)果悉尾。但是多處理器系統(tǒng)則截然不同突那。在多 CPU 機(jī)器上,兩個(gè)單獨(dú)的處理器可能會(huì)在幾乎同一時(shí)刻(或者构眯,就在同一時(shí)刻)執(zhí)行上述賦值語句愕难。不要忘了,這時(shí)對(duì)內(nèi)存的修改需要先從 L1 寫入 L2高速緩存、然后才寫入主存猫缭。(SMP 機(jī)器并不只是增加了處理器而已葱弟;它還有用來仲裁對(duì) RAM 存取的特殊硬件。)最終猜丹,根本無法搞清在寫入主存的競爭中芝加,哪個(gè) CPU 將會(huì)"勝出"。要產(chǎn)生可預(yù)測的代碼射窒,應(yīng)使用互斥對(duì)象藏杖。互斥對(duì)象將插入一道"內(nèi)存關(guān)卡"脉顿,由它來確保對(duì)主存的寫入按照線程鎖定互斥對(duì)象的順序進(jìn)行蝌麸。

考慮一種以 32 位塊為單位更新主存的 SMP 體系結(jié)構(gòu)。如果未使用互斥對(duì)象就對(duì)一個(gè)64 位整數(shù)進(jìn)行加一操作艾疟,整數(shù)的最高 4 位字節(jié)可能來自一個(gè) CPU来吩,而其它 4 個(gè)字節(jié)卻來自另一 CPU。糟糕吧蔽莱!最糟糕的是弟疆,使用差勁的技術(shù),您的程序在重要客戶的系統(tǒng)上有可能不是很長時(shí)間才崩潰一次盗冷,就是早上三點(diǎn)鐘就崩潰兽间。

互斥對(duì)象

如果放置了過多的互斥對(duì)象,代碼就沒有什么并發(fā)性可言正塌,運(yùn)行起來也比單線程解決方案慢嘀略。如果放置了過少的互斥對(duì)象,代碼將出現(xiàn)奇怪和令人尷尬的錯(cuò)誤乓诽。幸運(yùn)的是帜羊,有一個(gè)中間立場。

首先鸠天,互斥對(duì)象是用于串行化存取*共享數(shù)據(jù)*讼育。不要對(duì)非共享數(shù)據(jù)使用互斥對(duì)象,并且稠集,如果程序邏輯確保任何時(shí)候都只有一個(gè)線程能存取特定數(shù)據(jù)結(jié)構(gòu)奶段,那么也不要使用互斥對(duì)象。

其次剥纷,如果要使用共享數(shù)據(jù)痹籍,那么在讀、寫共享數(shù)據(jù)時(shí)都應(yīng)使用互斥對(duì)象晦鞋。用pthread_mutex_lock() 和 pthread_mutex_unlock() 把讀寫部分保護(hù)起來蹲缠,或者在程序中不固定的地方隨機(jī)使用它們棺克。學(xué)會(huì)從一個(gè)線程的角度來審視代碼,并確保程序中每一個(gè)線程對(duì)內(nèi)存的觀點(diǎn)都是一致和合適的线定。為了熟悉互斥對(duì)象的用法娜谊,最初可能要花好幾個(gè)小時(shí)來編寫代碼,但是很快就會(huì)習(xí)慣并且*也*不必多想就能夠正確使用它們斤讥。

使用調(diào)用:初始化

現(xiàn)在該來看看使用互斥對(duì)象的各種不同方法了纱皆。讓我們從初始化開始。我們使用了靜態(tài)初始化方法芭商。這需要聲明一個(gè) pthread_mutex_t 變量抹剩,并賦給它常數(shù)PTHREAD_MUTEX_INITIALIZER:

pthread_mutex_t?mymutex=PTHREAD_MUTEX_INITIALIZER;

很簡單吧。但是還可以動(dòng)態(tài)地創(chuàng)建互斥對(duì)象蓉坎。當(dāng)代碼使用 malloc() 分配一個(gè)新的互斥對(duì)象時(shí)澳眷,使用這種動(dòng)態(tài)方法。此時(shí)蛉艾,靜態(tài)初始化方法是行不通的钳踊,并且應(yīng)當(dāng)使用例程pthread_mutex_init():

int?pthread_mutex_init(?pthread_mutex_t?*mymutex,?const?pthread_mutexattr_t?*attr)


正如所示,pthread_mutex_init 接受一個(gè)指針作為參數(shù)以初始化為互斥對(duì)象勿侯,該指針指向一塊已分配好的內(nèi)存區(qū)拓瞪。第二個(gè)參數(shù),可以接受一個(gè)可選的 pthread_mutexattr_t 指針助琐。這個(gè)結(jié)構(gòu)可用來設(shè)置各種互斥對(duì)象屬性祭埂。但是通常并不需要這些屬性,所以正常做法是指定 NULL兵钮。

一旦使用 pthread_mutex_init() 初始化了互斥對(duì)象蛆橡,就應(yīng)使用 pthread_mutex_destroy() 消除它。pthread_mutex_destroy() 接受一個(gè)指向 pthread_mutext_t 的指針作為參數(shù)掘譬,并釋放創(chuàng)建互斥對(duì)象時(shí)分配給它的任何資源泰演。請(qǐng)注意, pthread_mutex_destroy()不會(huì)釋放用來存儲(chǔ) pthread_mutex_t 的內(nèi)存葱轩。釋放自己的內(nèi)存完全取決于您睦焕。還必須注意一點(diǎn),pthread_mutex_init() 和 pthread_mutex_destroy() 成功時(shí)都返回零靴拱。

使用調(diào)用:鎖定

pthread_mutex_lock(pthread_mutex_t?*mutex)

pthread_mutex_unlock(pthread_mutex_t?*mutex)

pthread_mutex_trylock(pthread_mutex_t?*mutex)

pthread_mutex_lock() 接受一個(gè)指向互斥對(duì)象的指針作為參數(shù)以將其鎖定垃喊。如果碰巧已經(jīng)鎖定了互斥對(duì)象,調(diào)用者將進(jìn)入睡眠狀態(tài)袜炕。函數(shù)返回時(shí)本谜,將喚醒調(diào)用者(顯然)并且調(diào)用者還將保留該鎖。函數(shù)調(diào)用成功時(shí)返回零妇蛀,失敗時(shí)返回非零的錯(cuò)誤代碼耕突。

pthread_mutex_unlock() 與 pthread_mutex_lock() 相配合笤成,它把線程已經(jīng)加鎖的互斥對(duì)象解鎖评架。始終應(yīng)該盡快對(duì)已加鎖的互斥對(duì)象進(jìn)行解鎖(以提高性能)眷茁。并且絕對(duì)不要對(duì)您未保持鎖的互斥對(duì)象進(jìn)行解鎖操作(否則,pthread_mutex_unlock() 調(diào)用將失敗并帶一個(gè)非零的 EPERM 返回值)纵诞。

當(dāng)線程正在做其它事情的時(shí)候(由于互斥對(duì)象當(dāng)前是鎖定的)上祈,如果希望鎖定互斥對(duì)象,這個(gè)調(diào)用就相當(dāng)方便浙芙。調(diào)用 pthread_mutex_trylock() 時(shí)將嘗試鎖定互斥對(duì)象登刺。如果互斥對(duì)象當(dāng)前處于解鎖狀態(tài),那么您將獲得該鎖并且函數(shù)將返回零嗡呼。然而纸俭,如果互斥對(duì)象已鎖定,這個(gè)調(diào)用也不會(huì)阻塞南窗。當(dāng)然揍很,它會(huì)返回非零的 EBUSY 錯(cuò)誤值。然后可以繼續(xù)做其它事情万伤,稍后再嘗試鎖定窒悔。

等待條件發(fā)生

互斥對(duì)象是線程程序必需的工具,但它們并非萬能的敌买。例如简珠,如果線程正在等待共享數(shù)據(jù)內(nèi)某個(gè)條件出現(xiàn),那會(huì)發(fā)生什么呢虹钮?代碼可以反復(fù)對(duì)互斥對(duì)象鎖定和解鎖聋庵,以檢查值的任何變化。同時(shí)芙粱,還要快速將互斥對(duì)象解鎖珍策,以便其它線程能夠進(jìn)行任何必需的更改。這是一種非痴梗可怕的方法攘宙,因?yàn)榫€程需要在合理的時(shí)間范圍內(nèi)頻繁地循環(huán)檢測變化。

在每次檢查之間拐迁,可以讓調(diào)用線程短暫地進(jìn)入睡眠蹭劈,比如睡眠三秒鐘,但是因此線程代碼就無法最快作出響應(yīng)线召。真正需要的是這樣一種方法铺韧,當(dāng)線程在等待滿足某些條件時(shí)使線程進(jìn)入睡眠狀態(tài)。一旦條件滿足缓淹,還需要一種方法以喚醒因等待滿足特定條件而睡眠的線程哈打。如果能夠做到這一點(diǎn)塔逃,線程代碼將是非常高效的,并且不會(huì)占用寶貴的互斥對(duì)象鎖料仗。這正是 POSIX 條件變量能做的事湾盗!

而 POSIX 條件變量將是我下一篇文章的主題,其中將說明如何正確使用條件變量立轧。到那時(shí)格粪,您已經(jīng)越來越熟悉線程,我將在下一篇文章中加快進(jìn)度氛改。這樣帐萎,在下一篇文章的結(jié)尾就能放上一個(gè)相對(duì)復(fù)雜的線程程序。

說到等到條件產(chǎn)生胜卤,下次再見疆导!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市葛躏,隨后出現(xiàn)的幾起案子澈段,更是在濱河造成了極大的恐慌,老刑警劉巖紫新,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件均蜜,死亡現(xiàn)場離奇詭異,居然都是意外死亡芒率,警方通過查閱死者的電腦和手機(jī)囤耳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偶芍,“玉大人充择,你說我怎么就攤上這事》梭埃” “怎么了椎麦?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長材彪。 經(jīng)常有香客問我观挎,道長,這世上最難降的妖魔是什么段化? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任嘁捷,我火速辦了婚禮,結(jié)果婚禮上显熏,老公的妹妹穿的比我還像新娘雄嚣。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布缓升。 她就那樣靜靜地躺著鼓鲁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪港谊。 梳的紋絲不亂的頭發(fā)上骇吭,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音封锉,去河邊找鬼绵跷。 笑死膘螟,一個(gè)胖子當(dāng)著我的面吹牛成福,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荆残,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼奴艾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了内斯?” 一聲冷哼從身側(cè)響起蕴潦,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俘闯,沒想到半個(gè)月后潭苞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡真朗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年此疹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遮婶。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝗碎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旗扑,到底是詐尸還是另有隱情蹦骑,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布臀防,位于F島的核電站眠菇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏袱衷。R本人自食惡果不足惜捎废,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祟昭。 院中可真熱鬧缕坎,春花似錦、人聲如沸篡悟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荷腊,卻和暖如春艳悔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背女仰。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工猜年, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疾忍。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓乔外,卻偏偏與公主長得像,于是被迫代替她去往敵國和親一罩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杨幼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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