詳解linux多線程——互斥鎖庇忌、條件變量、讀寫鎖舰褪、自旋鎖皆疹、信號量

一、互斥鎖(同步)

??在多任務操作系統(tǒng)中占拍,同時運行的多個任務可能都需要使用同一種資源略就。這個過程有點類似于,公司部門里晃酒,我在使用著打印機打印東西的同時(還沒有打印完)表牢,別人剛好也在此刻使用打印機打印東西,如果不做任何處理的話贝次,打印出來的東西肯定是錯亂的崔兴。

??在線程里也有這么一把鎖——互斥鎖(mutex),互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問,互斥鎖只有兩種狀態(tài),即上鎖( lock )和解鎖( unlock )敲茄。

【互斥鎖的特點】:

1. 原子性:把一個互斥量鎖定為一個原子操作位谋,這意味著操作系統(tǒng)(或pthread函數(shù)庫)保證了如果一個線程鎖定了一個互斥量,沒有其他線程在同一時間可以成功鎖定這個互斥量折汞;

2. 唯一性:如果一個線程鎖定了一個互斥量倔幼,在它解除鎖定之前,沒有其他線程可以鎖定這個互斥量爽待;

3. 非繁忙等待:如果一個線程已經(jīng)鎖定了一個互斥量损同,第二個線程又試圖去鎖定這個互斥量,則第二個線程將被掛起(不占用任何cpu資源)鸟款,直到第一個線程解除對這個互斥量的鎖定為止膏燃,第二個線程則被喚醒并繼續(xù)執(zhí)行,同時鎖定這個互斥量何什。

【互斥鎖的操作流程如下】:

1. 在訪問共享資源后臨界區(qū)域前组哩,對互斥鎖進行加鎖;

2. 在訪問完成后釋放互斥鎖導上的鎖处渣。在訪問完成后釋放互斥鎖導上的鎖伶贰;

3. 對互斥鎖進行加鎖后,任何其他試圖再次對互斥鎖加鎖的線程將會被阻塞罐栈,直到鎖被釋放黍衙。對互斥鎖進行加鎖后,任何其他試圖再次對互斥鎖加鎖的線程將會被阻塞荠诬,直到鎖被釋放琅翻。

#include<pthread.h>

#include <time.h>

// 初始化一個互斥鎖。

int pthread_mutex_init(pthread_mutex_t *mutex,

const pthread_mutexattr_t *attr);

// 對互斥鎖上鎖柑贞,若互斥鎖已經(jīng)上鎖方椎,則調(diào)用者一直阻塞,

// 直到互斥鎖解鎖后再上鎖钧嘶。

int pthread_mutex_lock(pthread_mutex_t *mutex);

// 調(diào)用該函數(shù)時棠众,若互斥鎖未加鎖,則上鎖康辑,返回 0摄欲;

// 若互斥鎖已加鎖,則函數(shù)直接返回失敗疮薇,即 EBUSY胸墙。

int pthread_mutex_trylock(pthread_mutex_t *mutex);

// 當線程試圖獲取一個已加鎖的互斥量時,pthread_mutex_timedlock 互斥量

// 原語允許綁定線程阻塞時間按咒。即非阻塞加鎖互斥量迟隅。

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,

const struct timespec *restrict abs_timeout);

// 對指定的互斥鎖解鎖但骨。

int pthread_mutex_unlock(pthread_mutex_t *mutex);

// 銷毀指定的一個互斥鎖≈窍互斥鎖在使用完畢后奔缠,

// 必須要對互斥鎖進行銷毀,以釋放資源吼野。

int pthread_mutex_destroy(pthread_mutex_t *mutex);

【Demo】(阻塞模式):

//使用互斥量解決多線程搶占資源的問題

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<pthread.h>

#include<string.h>

char*buf[5];//字符指針數(shù)組全局變量

intpos;//用于指定上面數(shù)組的下標

//1.定義互斥量

pthread_mutex_tmutex;

void*task(void*p)

{

//3.使用互斥量進行加鎖

pthread_mutex_lock(&mutex);

buf[pos]=(char*)p;

sleep(1);

pos++;

//4.使用互斥量進行解鎖

pthread_mutex_unlock(&mutex);

}

intmain(void)

{

//2.初始化互斥量,默認屬性

pthread_mutex_init(&mutex,NULL);

//1.啟動一個線程向數(shù)組中存儲內(nèi)容

pthread_ttid,tid2;

pthread_create(&tid,NULL,task,(void*)"zhangfei");

pthread_create(&tid2,NULL,task,(void*)"guanyu");

//2.主線程進程等待,并且打印最終的結果

pthread_join(tid,NULL);

pthread_join(tid2,NULL);

//5.銷毀互斥量

pthread_mutex_destroy(&mutex);

inti=0;

printf("字符指針數(shù)組中的內(nèi)容是:");

for(i=0;i<pos;++i)

{

printf("%s", buf[i]);

? ? }

? ? printf("\n");

return0;

}

【Demo】(非阻塞模式):

#include

#include #include #include

intmain (void)

{interr;

structtimespec tout;

structtm *tmp;

char buf[64];

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;? ? ? ? pthread_mutex_lock (&lock);? ? printf ("mutex is locked\n");

clock_gettime (CLOCK_REALTIME, &tout);? ? tmp = localtime (&tout.tv_sec);? ? strftime (buf, sizeof (buf),"%r", tmp);

printf ("current time is %s\n", buf);

tout.tv_sec +=10;

err = pthread_mutex_timedlock (&lock, &tout);? ? clock_gettime (CLOCK_REALTIME, &tout);? ? tmp = localtime (&tout.tv_sec);? ? strftime (buf, sizeof (buf),"%r", tmp);

printf ("the time is now %s\n", buf);

if(err ==0)

printf ("mutex locked again\n");

else

printf ("can`t lock mutex again:%s\n", strerror (err));

return0;

}

需要C/C++ Linux服務器架構師學習資料加qun(563998835)(資料包括C/C++校哎,Linux,golang技術瞳步,Nginx闷哆,ZeroMQ,MySQL单起,Redis抱怔,fastdfs,MongoDB嘀倒,ZK屈留,流媒體,CDN测蘑,P2P灌危,K8S,Docker碳胳,TCP/IP乍狐,協(xié)程,DPDK固逗,ffmpeg等),免費分享

二藕帜、條件變量(同步)

??與互斥鎖不同烫罩,條件變量是用來等待而不是用來上鎖的。條件變量用來自動阻塞一個線程洽故,直 到某特殊情況發(fā)生為止贝攒。通常條件變量和互斥鎖同時使用。

??條件變量使我們可以睡眠等待某種條件出現(xiàn)时甚。條件變量是利用線程間共享的全局變量進行同步 的一種機制隘弊,主要包括兩個動作:

一個線程等待"條件變量的條件成立"而掛起;

另一個線程使 “條件成立”(給出條件成立信號)荒适。

【原理】:

??條件的檢測是在互斥鎖的保護下進行的梨熙。線程在改變條件狀態(tài)之前必須首先鎖住互斥量。如果一個條件為假刀诬,一個線程自動阻塞咽扇,并釋放等待狀態(tài)改變的互斥鎖。如果另一個線程改變了條件,它發(fā)信號給關聯(lián)的條件變量质欲,喚醒一個或多個等待它的線程树埠,重新獲得互斥鎖,重新評價條件嘶伟。如果兩進程共享可讀寫的內(nèi)存怎憋,條件變量 可以被用來實現(xiàn)這兩進程間的線程同步。

【條件變量的操作流程如下】:

1. 初始化:init()或者pthread_cond_tcond=PTHREAD_COND_INITIALIER九昧;屬性置為NULL绊袋;

2. 等待條件成立:pthread_wait,pthread_timewait.wait()釋放鎖,并阻塞等待條件變量為真 timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)耽装;

3. 激活條件變量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)

4. 清除條件變量:destroy;無線程等待,否則返回EBUSY清除條件變量:destroy;無線程等待,否則返回EBUSY

#include<pthread.h>

// 初始化條件變量

int pthread_cond_init(pthread_cond_t *cond,

pthread_condattr_t *cond_attr);

// 阻塞等待

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

// 超時等待

int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,

const timespec *abstime);

// 解除所有線程的阻塞

int pthread_cond_destroy(pthread_cond_t *cond);

// 至少喚醒一個等待該條件的線程

int pthread_cond_signal(pthread_cond_t *cond);

// 喚醒等待該條件的所有線程

int pthread_cond_broadcast(pthread_cond_t *cond);?

1愤炸、線程的條件變量實例1

??Jack開著一輛出租車來到一個站點停車,看見沒人就走了掉奄。過段時間规个,Susan來到站點準備乘車,但是沒有來姓建,于是就等著诞仓。過了一會Mike開著車來到了這個站點,Sunsan就上了Mike的車走了速兔。如圖所示:

#include

#include ? #include ? #include ? ? pthread_cond_t taxicond = PTHREAD_COND_INITIALIZER;? pthread_mutex_t taximutex = PTHREAD_MUTEX_INITIALIZER;? ? void *traveler_arrive(void *name)? {char*p = (char*)name;

printf ("Travelr: %s need a taxi now!\n", p);

// 加鎖墅拭,把信號量加入隊列,釋放信號量? ? pthread_mutex_lock(&taximutex);? ? ? pthread_cond_wait(&taxicond, &taximutex);? ? ? pthread_mutex_unlock(&taximutex);? ? ? printf ("traveler: %s now got a taxi!\n", p);

pthread_exit(NULL);? }? ? void *taxi_arrive(void *name)? {char*p = (char*)name;

printf ("Taxi: %s arrives.\n", p);

// 給線程或者條件發(fā)信號涣狗,一定要在改變條件狀態(tài)后再給線程發(fā)信號? ? pthread_cond_signal(&taxicond);? ? ? pthread_exit(NULL);? }? ? int main (int argc,char**argv)

{char*name;

pthread_t thread;? ? ? pthread_attr_t threadattr; // 線程屬性? ? pthread_attr_init(&threadattr);? // 線程屬性初始化? ? ? // 創(chuàng)建三個線程? ? name ="Jack";

pthread_create(&thread, &threadattr, taxi_arrive, (void *)name);? ? ? sleep(1);

name ="Susan";

pthread_create(&thread, &threadattr, traveler_arrive, (void *)name);? ? ? sleep(1);

name ="Mike";

pthread_create(&thread, &threadattr, taxi_arrive, (void *)name);? ? ? sleep(1);

return0;

}

2谍婉、線程的條件變量實例2

??Jack開著一輛出租車來到一個站點停車,看見沒人就等著镀钓。過段時間穗熬,Susan來到站點準備乘車看見了Jack的出租車,于是就上去了丁溅。過了一會Mike開著車來到了這個站點唤蔗,看見沒人救等著。如圖所示:

#include

#include #include #include int travelercount =0;

pthread_cond_t taxicond = PTHREAD_COND_INITIALIZER;pthread_mutex_t taximutex = PTHREAD_MUTEX_INITIALIZER; void *traveler_arrive(void *name){char*p = (char*)name;

pthread_mutex_lock(&taximutex);? ? printf ("traveler: %s need a taxi now!\n", p);

travelercount++;? ? pthread_cond_wait(&taxicond, &taximutex);? ? ? ? ? ? ? ? pthread_mutex_unlock(&taximutex);? ? printf ("traveler: %s now got a taxi!\n", p);

pthread_exit(NULL);} void *taxi_arrive(void *name){char*p = (char*)name;

printf ("Taxi: %s arrives.\n", p);

for(;;)

{if(travelercount)

{? ? ? ? ? ? pthread_cond_signal(&taxicond);? ? ? ? ? ? travelercount--;break;

}? ? }? ? pthread_exit(NULL);} int main (int argc,char**argv)

{char*name;

pthread_t thread;? ? pthread_attr_t threadattr;? ? pthread_attr_init(&threadattr);? ? name ="Jack";

pthread_create(&thread, &threadattr, taxi_arrive, name);? ? sleep(1);

name ="Susan";

pthread_create(&thread, &threadattr, traveler_arrive, name);? ? sleep(3);

name ="Mike";

pthread_create(&thread, &threadattr, taxi_arrive, name);? ? sleep(4);

return0;

}

3窟赏、虛假喚醒(spurious wakeup)

??虛假喚醒(spurious wakeup)在采用條件等待時:

while(條件不滿足)

{condition_wait(cond, mutex);

}// 而不是:?

If( 條件不滿足 )

{?

? Condition_wait(cond,mutex);?

}?

這是因為可能會存在虛假喚醒”spurious wakeup”的情況妓柜。

??也就是說,即使沒有線程調(diào)用condition_signal, 原先調(diào)用condition_wait的函數(shù)也可能會返回涯穷。此時線程被喚醒了棍掐,但是條件并不滿足,這個時候如果不對條件進行檢查而往下執(zhí)行拷况,就可能會導致后續(xù)的處理出現(xiàn)錯誤塌衰。

??虛假喚醒在linux的多處理器系統(tǒng)中/在程序接收到信號時可能回發(fā)生诉稍。在Windows系統(tǒng)和JAVA虛擬機上也存在。在系統(tǒng)設計時應該可以避免虛假喚醒最疆,但是這會影響條件變量的執(zhí)行效率杯巨,而既然通過while循環(huán)就能避免虛假喚醒造成的錯誤,因此程序的邏輯就變成了while循環(huán)的情況努酸。

四服爷、讀寫鎖(同步)

??讀寫鎖與互斥量類似,不過讀寫鎖允許更改的并行性获诈,也叫共享互斥鎖仍源。互斥量要么是鎖住狀態(tài)舔涎,要么就是不加鎖狀態(tài)笼踩,而且一次只有一個線程可以對其加鎖。讀寫鎖可以有3種狀態(tài):讀模式下加鎖狀態(tài)亡嫌、寫模式加鎖狀態(tài)嚎于、不加鎖狀態(tài)。

??一次只有一個線程可以占有寫模式的讀寫鎖挟冠,但是多個線程可以同時占有讀模式的讀寫鎖(允許多個線程讀但只允許一個線程寫)于购。

【讀寫鎖的特點】:

如果有其它線程讀數(shù)據(jù),則允許其它線程執(zhí)行讀操作知染,但不允許寫操作肋僧;

如果有其它線程寫數(shù)據(jù),則其它線程都不允許讀控淡、寫操作嫌吠。

【讀寫鎖的規(guī)則】:

如果某線程申請了讀鎖,其它線程可以再申請讀鎖掺炭,但不能申請寫鎖居兆;

如果某線程申請了寫鎖,其它線程不能申請讀鎖竹伸,也不能申請寫鎖。

讀寫鎖適合于對數(shù)據(jù)結構的讀次數(shù)比寫次數(shù)多得多的情況簇宽。

#include<pthread.h>

// 初始化讀寫鎖

int pthread_rwlock_init(pthread_rwlock_t *rwlock,

const pthread_rwlockattr_t *attr);

// 申請讀鎖

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );

// 申請寫鎖

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

// 嘗試以非阻塞的方式來在讀寫鎖上獲取寫鎖勋篓,

// 如果有任何的讀者或?qū)懻叱钟性撴i,則立即失敗返回魏割。

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

// 解鎖

int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);

// 銷毀讀寫鎖

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

【Demo】:

// 一個使用讀寫鎖來實現(xiàn)4個線程讀寫一段數(shù)據(jù)是實例譬嚣。

// 在此示例程序中,共創(chuàng)建了4個線程钞它,

// 其中兩個線程用來寫入數(shù)據(jù)拜银,兩個線程用來讀取數(shù)據(jù)#include ? #include ? #include ? pthread_rwlock_t rwlock; //讀寫鎖? int num =1;

//讀操作殊鞭,其他線程允許讀操作,卻不允許寫操作? void *fun1(void *arg)

{while(1)

{? ? ? ? ? pthread_rwlock_rdlock(&rwlock);? ? ? ? printf("read num first == %d\n", num);

pthread_rwlock_unlock(&rwlock);? ? ? ? sleep(1);

}}? //讀操作尼桶,其他線程允許讀操作操灿,卻不允許寫操作? void *fun2(void *arg)

{while(1)

{? ? ? ? pthread_rwlock_rdlock(&rwlock);? ? ? ? printf("read num second == %d\n", num);

pthread_rwlock_unlock(&rwlock);? ? ? ? sleep(2);

}} //寫操作,其它線程都不允許讀或?qū)懖僮? void *fun3(void *arg)

{while(1)

{? ? ? ? pthread_rwlock_wrlock(&rwlock);? ? ? ? num++;? ? ? ? printf("write thread first\n");

pthread_rwlock_unlock(&rwlock);? ? ? ? sleep(2);

}} //寫操作泵督,其它線程都不允許讀或?qū)懖僮? void *fun4(void *arg)

{while(1)

{? ? ? ? ? pthread_rwlock_wrlock(&rwlock);? ? ? ? ? num++;? ? ? ? ? printf("write thread second\n");

pthread_rwlock_unlock(&rwlock);? ? ? ? ? sleep(1);

}? }? ? int main()? {? ? ? pthread_t ptd1, ptd2, ptd3, ptd4;? ? ? ? ? ? pthread_rwlock_init(&rwlock, NULL);//初始化一個讀寫鎖? ? ? ? ? ? //創(chuàng)建線程? ? ? pthread_create(&ptd1, NULL, fun1, NULL);? ? ? pthread_create(&ptd2, NULL, fun2, NULL);? ? ? pthread_create(&ptd3, NULL, fun3, NULL);? ? ? pthread_create(&ptd4, NULL, fun4, NULL);? ? ? ? ? ? //等待線程結束趾盐,回收其資源? ? ? pthread_join(ptd1, NULL);? ? ? pthread_join(ptd2, NULL);? ? ? pthread_join(ptd3, NULL);? ? ? pthread_join(ptd4, NULL);? ? ? ? ? ? pthread_rwlock_destroy(&rwlock);//銷毀讀寫鎖return0;

}

五、自旋鎖(同步)

??自旋鎖與互斥量功能一樣小腊,唯一一點不同的就是互斥量阻塞后休眠讓出cpu救鲤,而自旋鎖阻塞后不會讓出cpu,會一直忙等待秩冈,直到得到鎖本缠。

??自旋鎖在用戶態(tài)使用的比較少,在內(nèi)核使用的比較多入问!自旋鎖的使用場景:鎖的持有時間比較短丹锹,或者說小于2次上下文切換的時間。

??自旋鎖在用戶態(tài)的函數(shù)接口和互斥量一樣队他,把pthread_mutex_xxx()中mutex換成spin卷仑,如:pthread_spin_init()。

六麸折、信號量(同步與互斥)

??信號量廣泛用于進程或線程間的同步和互斥锡凝,信號量本質(zhì)上是一個非負的整數(shù)計數(shù)器,它被用來控制對公共資源的訪問垢啼。

??編程時可根據(jù)操作信號量值的結果判斷是否對公共資源具有訪問的權限窜锯,當信號量值大于 0 時,則可以訪問芭析,否則將阻塞锚扎。PV 原語是對信號量的操作,一次 P 操作使信號量減1馁启,一次 V 操作使信號量加1驾孔。

#include<semaphore.h>

// 初始化信號量

int sem_init(sem_t *sem, int pshared, unsigned int value);

// 信號量 P 操作(減 1)

int sem_wait(sem_t *sem);

// 以非阻塞的方式來對信號量進行減 1 操作

int sem_trywait(sem_t *sem);

// 信號量 V 操作(加 1)

int sem_post(sem_t *sem);

// 獲取信號量的值

int sem_getvalue(sem_t *sem, int *sval);

// 銷毀信號量

int sem_destroy(sem_t *sem);

【信號量用于同步】:

//信號量用于同步實例

#include<stdio.h>

#include<unistd.h>

#include<pthread.h>

#include<semaphore.h>

sem_tsem_g,sem_p;//定義兩個信號量

charch='a';

void*pthread_g(void*arg)//此線程改變字符ch的值

{

while(1)

{

sem_wait(&sem_g);

ch++;

sleep(1);

sem_post(&sem_p);

}

}

void*pthread_p(void*arg)//此線程打印ch的值

{

while(1)

{

sem_wait(&sem_p);

printf("%c",ch);

fflush(stdout);

sem_post(&sem_g);

}

}

intmain(intargc,char*argv[])

{

pthread_ttid1,tid2;

sem_init(&sem_g,0,0);//初始化信號量為0

sem_init(&sem_p,0,1);//初始化信號量為1

//創(chuàng)建兩個線程

pthread_create(&tid1,NULL,pthread_g,NULL);

pthread_create(&tid2,NULL,pthread_p,NULL);

//回收線程

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

return0;

}

【信號量用于互斥】:

//信號量用于互斥實例

#include<stdio.h>

#include<pthread.h>

#include<unistd.h>

#include<semaphore.h>

sem_tsem;//信號量

voidprinter(char*str)

{

sem_wait(&sem);//減一,p操作

while(*str)//輸出字符串(如果不用互斥惯疙,此處可能會被其他線程入侵)

{

putchar(*str);

fflush(stdout);

str++;

sleep(1);

}

printf("\n");

sem_post(&sem);//加一翠勉,v操作

}

void*thread_fun1(void*arg)

{

char*str1="hello";

printer(str1);

}

void*thread_fun2(void*arg)

{

char*str2="world";

printer(str2);

}

intmain(void)

{

pthread_ttid1,tid2;

sem_init(&sem,0,1);//初始化信號量,初始值為1

//創(chuàng)建2個線程

pthread_create(&tid1,NULL,thread_fun1,NULL);

pthread_create(&tid2,NULL,thread_fun2,NULL);

//等待線程結束霉颠,回收其資源

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

sem_destroy(&sem);//銷毀信號量

return0;

}

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末对碌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蒿偎,更是在濱河造成了極大的恐慌朽们,老刑警劉巖怀读,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骑脱,居然都是意外死亡菜枷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門惜姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犁跪,“玉大人,你說我怎么就攤上這事歹袁】姥埽” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵条舔,是天一觀的道長枫耳。 經(jīng)常有香客問我,道長孟抗,這世上最難降的妖魔是什么迁杨? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮凄硼,結果婚禮上铅协,老公的妹妹穿的比我還像新娘。我一直安慰自己摊沉,他們只是感情好狐史,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著说墨,像睡著了一般骏全。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尼斧,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天姜贡,我揣著相機與錄音,去河邊找鬼棺棵。 笑死楼咳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的烛恤。 我是一名探鬼主播母怜,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棒动!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宾添,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤船惨,失蹤者是張志新(化名)和其女友劉穎柜裸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粱锐,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡疙挺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了怜浅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铐然。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖恶座,靈堂內(nèi)的尸體忽然破棺而出搀暑,到底是詐尸還是另有隱情,我是刑警寧澤跨琳,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布自点,位于F島的核電站,受9級特大地震影響脉让,放射性物質(zhì)發(fā)生泄漏桂敛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一溅潜、第九天 我趴在偏房一處隱蔽的房頂上張望术唬。 院中可真熱鬧,春花似錦滚澜、人聲如沸粗仓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潦牛。三九已至,卻和暖如春挡育,著一層夾襖步出監(jiān)牢的瞬間巴碗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工即寒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留橡淆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓母赵,卻偏偏與公主長得像逸爵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凹嘲,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359