APUE讀書筆記-15進(jìn)程內(nèi)部通信(8)

9翩概、共享內(nèi)存

共享內(nèi)存允許兩個(gè)或者更多的進(jìn)程共享一塊指定區(qū)域的內(nèi)存坯认。這個(gè)是最快的IPC高职,因?yàn)閿?shù)據(jù)不需要在客戶和服務(wù)進(jìn)程之間進(jìn)行拷貝了糙置。共享內(nèi)存唯一一個(gè)需要注意的地方就是同步多個(gè)進(jìn)程訪問(wèn)共享內(nèi)存胁后。如果服務(wù)進(jìn)程正在將數(shù)據(jù)放到共享內(nèi)存區(qū)域蝙砌,那么客戶進(jìn)程不應(yīng)當(dāng)在服務(wù)進(jìn)程做完之前訪問(wèn)這個(gè)共享內(nèi)存中的數(shù)據(jù)怎棱。一般來(lái)說(shuō)旁赊,使用信號(hào)量來(lái)同步共享內(nèi)存的訪問(wèn)(但是前面我們也看到了愉阎,記錄鎖也行)绞蹦。

Single UNIX Specification在共享內(nèi)存對(duì)象的實(shí)時(shí)擴(kuò)展選項(xiàng)中包含一系列的訪問(wèn)共享內(nèi)存的接口集合,但是這里我們不討論實(shí)時(shí)方面的擴(kuò)展榜旦。

內(nèi)核對(duì)于每個(gè)共享內(nèi)存段都維護(hù)一個(gè)至少包含如下成員的數(shù)據(jù)結(jié)構(gòu):

struct shmid_ds {
        struct ipc_perm  shm_perm;    /* see Section 15.6.2 */
        size_t           shm_segsz;   /* size of segment in bytes */
        pid_t            shm_lpid;    /* pid of last shmop() */
        pid_t            shm_cpid;    /* pid of creator */
        shmatt_t         shm_nattch;  /* number of current attaches */
        time_t           shm_atime;   /* last-attach time */
        time_t           shm_dtime;   /* last-detach time */
        time_t           shm_ctime;   /* last-change time */
        .
};

(其他的實(shí)現(xiàn)可以添加其他的額外成員)

類型shmatt_t被定義成一個(gè)無(wú)符號(hào)的整數(shù)幽七,其大小至少和unsigned short那么大。文中給出了影響共享內(nèi)存的系統(tǒng)限制溅呢。這里就不列舉了锉走。

shmget

一般首先調(diào)用的函數(shù)是shmget,用來(lái)獲得共享內(nèi)存標(biāo)識(shí)藕届。

#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);

返回值:如果成功挪蹭,返回共享內(nèi)存的ID,如果錯(cuò)誤返回1休偶。

前面我們討論了將一個(gè)關(guān)鍵字轉(zhuǎn)換成標(biāo)識(shí)的方法梁厉,以及創(chuàng)建一個(gè)新的共享內(nèi)存段和對(duì)已經(jīng)存在的共享內(nèi)存段的引用。當(dāng)創(chuàng)建一個(gè)新的共享內(nèi)存段的時(shí)候踏兜,shmid_ds結(jié)構(gòu)變量的如下成員將會(huì)被初始化词顾。

  1. ipc_perm結(jié)構(gòu)如同前面描述的那樣被初始化(即所有的成員都會(huì)被初始化)。結(jié)構(gòu)的mode成員將會(huì)被設(shè)置成相應(yīng)的flag權(quán)限位碱妆。
  2. shm_lpid, shm_nattach, shm_atime, 和 shm_dtime 都被設(shè)置成0.
  3. shm_ctime 被設(shè)置成當(dāng)前時(shí)間肉盹。
  4. 被設(shè)置成要求的大小。

size參數(shù)表示共享內(nèi)存段的字節(jié)大小數(shù)目疹尾。具體的實(shí)現(xiàn)經(jīng)常會(huì)將大小向上圓整成系統(tǒng)頁(yè)大小的整數(shù)倍上忍,但是如果應(yīng)用程序如果指定的大小值不是系統(tǒng)頁(yè)的整數(shù)倍的話骤肛,那么最后一頁(yè)剩余的那個(gè)部分是不可用的。如果 創(chuàng)建一個(gè)新的共享內(nèi)存段的時(shí)候(一般都由服務(wù)進(jìn)程創(chuàng)建)窍蓝,我們必須指定它的size參數(shù) 腋颠。如果我們 引用一個(gè)已經(jīng)存在的共享內(nèi)存段(一般都由客戶進(jìn)程引用),我們可以指定size參數(shù)為0 吓笙。如果創(chuàng)建一個(gè)新的共享內(nèi)存段淑玫,那么這個(gè) 新創(chuàng)建的共享內(nèi)存段中的內(nèi)容被初始化成0

shmctl

shmctl函數(shù)用來(lái)處理各種類型的共享內(nèi)存操作面睛。

#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

返回值:如果成功絮蒿,返回OK,如果錯(cuò)誤返回1叁鉴。

cmd參數(shù)指定了如下的五個(gè)命令歌径,這五個(gè)命令用來(lái)操作shmid所指定的共享內(nèi)存段。

  • IPC_STAT 獲取共享內(nèi)存段的shmid_ds結(jié)構(gòu)亲茅,并將它存放在buf所指向的數(shù)據(jù)結(jié)構(gòu)指針中。
  • IPC_SET 根據(jù)buf指向的數(shù)據(jù)結(jié)構(gòu)狗准,設(shè)置共享內(nèi)存段相應(yīng)的shmid_ds結(jié)構(gòu)相關(guān)的如下三個(gè)成員:shm_perm.uid, shm_perm.gid, 和 shm_perm.mode克锣。這個(gè)命令可以被執(zhí)行的前提是:進(jìn)程的有效用戶ID等于shm_perm.cuid或者shm_perm.uid,或者進(jìn)程具有超級(jí)用戶權(quán)限腔长。
  • IPC_RMID 從系統(tǒng)中刪除共享內(nèi)存段袭祟。因?yàn)橛幸粋€(gè)維護(hù)共享內(nèi)存段的附加計(jì)數(shù)值(shmid_ds結(jié)構(gòu)變量中的shm_nattch成員), 共享內(nèi)存段不會(huì)被刪除捞附,這個(gè)狀態(tài)一直維持到最后一個(gè)使用這個(gè)共享內(nèi)存段的進(jìn)程終止巾乳,或者斷開(kāi)和它的連接 。無(wú)論這段內(nèi)存是否仍然在被使用鸟召,這個(gè) 共享內(nèi)存段的標(biāo)識(shí)會(huì)被立即刪除 胆绊,這樣就無(wú)法通過(guò)shmat函數(shù)將這段內(nèi)存再次附加了。這個(gè)命令可以被執(zhí)行的前提是:進(jìn)程的有效用戶ID等于shm_perm.cuid或者shm_perm.uid欧募,或者進(jìn)程具有超級(jí)用戶權(quán)限压状。

Linux和Solaris還提供了兩個(gè)命令,它們不屬于Single UNIX Specification的一個(gè)部分跟继。

  • SHM_LOCK 鎖住內(nèi)存中的共享內(nèi)存段种冬。這個(gè)命令只能被超級(jí)用戶執(zhí)行。
  • SHM_UNLOCK 解鎖共享內(nèi)存段舔糖。這個(gè)命令只能被超級(jí)用戶執(zhí)行娱两。

shmat

當(dāng)創(chuàng)建了一個(gè)共享內(nèi)存段的時(shí)候,進(jìn)程可以通過(guò)調(diào)用shmat來(lái)將這個(gè)共享內(nèi)存段附加到自己的地址空間上面金吗。

#include <sys/shm.h>
void *shmat(int shmid, const void *addr, int flag);

返回值:如果成功返回指向共享內(nèi)存段的指針十兢,如果錯(cuò)誤返回1趣竣。

共享內(nèi)存段所附加的在調(diào)用進(jìn)程中的地址取決于參數(shù)addr以及在flag中是否指定了SHM_RND。

  1. 如果addr是0纪挎,那么共享內(nèi)存段會(huì)被附加到內(nèi)核所選擇的第一個(gè)可用的地址期贫。建議這樣做。
  2. 如果addr是非空的并且沒(méi)有指定SHM_RND异袄,那么共享內(nèi)存段會(huì)被附加到addr所指定的地址上面通砍。
  3. 如果addr非空,并且SHM_RND被指定了烤蜕,那么共享內(nèi)存段會(huì)被附加到地址(addr - addr mod SHMLBA)上面封孙。SHM_RND命令表示取整。SHMLBA表示低地址界限倍數(shù)讽营,一般它為2的冪虎忌。這個(gè)運(yùn)算會(huì)導(dǎo)致地址被取整到下一個(gè)SHMLBA倍數(shù)了。

除非我們只在一種硬件類型上面運(yùn)行應(yīng)用程序(目前這個(gè)情況是不可能的)橱鹏,我們不應(yīng)當(dāng)指定共享內(nèi)存段被附加的地址膜蠢。相反我們應(yīng)當(dāng)指定addr為0以讓系統(tǒng)自己選擇地址。

如果SHM_RDONLY位被在flag中指定了莉兰,那么共享內(nèi)存段將會(huì)以只讀的方式被附加挑围。否則共享內(nèi)存段會(huì)以讀寫的方式被附加。

shmat返回的就是被附加的共享內(nèi)存段的地址糖荒,或者如果錯(cuò)誤返回1杉辙。如果shmat成功,那么內(nèi)核會(huì)增加和共享內(nèi)存段相關(guān)聯(lián)的shmid_ds中的shm_nattch計(jì)數(shù)捶朵。

shmdt

當(dāng)我們使用完共享內(nèi)存段之后蜘矢,我們調(diào)用shmdt將其斷開(kāi)。注意:這不會(huì)將共享內(nèi)存標(biāo)識(shí)以及它相關(guān)的數(shù)據(jù)結(jié)構(gòu)從系統(tǒng)中移除综看。標(biāo)識(shí)會(huì)一直存在品腹,直到有進(jìn)程(通常為服務(wù)進(jìn)程)特意地通過(guò)調(diào)用IPC_RMID命令的shmctl將它移除。

#include <sys/shm.h>
int shmdt(void *addr);
Returns: 0 if OK, 1 on error

返回值:如果成功红碑,返回0珍昨,如果錯(cuò)誤返回1。

addr參數(shù)就是之前調(diào)用shmat返回的值句喷。如果成功镣典,那么shmdt將會(huì)減少相關(guān)的shmid_ds結(jié)構(gòu)變量的shm_nattch計(jì)數(shù)成員變量。

舉例:不同的內(nèi)核通過(guò)傳入shmat參數(shù)0來(lái)附加地址段返回的地址依賴于系統(tǒng)唾琼。

下面的代碼展示了一個(gè)例子:

#include <sys/shm.h>
#define ARRAY_SIZE  40000
#define MALLOC_SIZE 100000
#define SHM_SIZE    100000
#define SHM_MODE    0600    /* 用戶 讀/寫 */

char    array[ARRAY_SIZE];  /* 非初始化的bss數(shù)據(jù)段 */
int main(void)
{
    int     shmid;
    char    *ptr, *shmptr;
        /*打印非初始化bss數(shù)據(jù)段(全局變量數(shù)組)地址*/
    printf("array[] from %lx to %lx\n", (unsigned long)&array[0], (unsigned long)&array[ARRAY_SIZE]);
        /*打印堆棧局部變量地址*/
    printf("stack around %lx\n", (unsigned long)&shmid);

    if ((ptr = malloc(MALLOC_SIZE)) == NULL)
        err_sys("malloc error");
        /*打印堆內(nèi)存地址*/
    printf("malloced from %lx to %lx\n", (unsigned long)ptr, (unsigned long)ptr+MALLOC_SIZE);

    if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0)
        err_sys("shmget error");
    if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1)
        err_sys("shmat error");
        /*打印共享內(nèi)存地址*/
    printf("shared memory attached from %lx to %lx\n", (unsigned long)shmptr, (unsigned long)shmptr+SHM_SIZE);

    if (shmctl(shmid, IPC_RMID, 0) < 0)
        err_sys("shmctl error");

    exit(0);
}

在基于intel的linux系統(tǒng)上面運(yùn)行這個(gè)程序兄春,輸入輸出如下:

$ ./a.out
array[] from 804a080 to 8053cc0
stack around bffff9e4
malloced from 8053cc8 to 806c368
shared memory attached from 40162000 to 4017a6a0

下圖展示了這個(gè)內(nèi)存布局,和我們前面說(shuō)過(guò)的類似锡溯。并且注意赶舆,共享內(nèi)存段放在堆棧下面哑姚。

            +----------------------+ \
high address|                      |  \Command Line arguments
            |                      |  /And environment variables.
            +----------------------+ /
            |    Stack             |<-----0xbffff9e4
            |                      |
            |                      |
            +----------------------+
            |   Shared Memory      |<----0x4017a6a0 \ Shared memory of
            |                      |<----0x40162000 / 100,000 bytes.
            +----------------------+
            |                      |
            |                      |<----0x0806c368 \ Malloc of
            |    Heap              |<----0x08053cc8 / 100,000 bytes.
            +----------------------+
            | uninitialized data   |<----0x08053cc0 \ array[] of
            |    (bss)             |<----0x0804a080 / 40,000 bytes.
            +----------------------+
            |                      |
            |   initialized data   |
            +----------------------+
            |                      |
            |        text          |
low address +----------------------+

使用mmap實(shí)現(xiàn)的共享內(nèi)存

使用mmap將文件內(nèi)容映射到地址空間上面和使用XSI IPC函數(shù)附加共享內(nèi)存段的地址的原理類似。不同的主要是芜茵,mmap映射的內(nèi)容由文件來(lái)存放叙量,而共享內(nèi)存映射的內(nèi)容沒(méi)有相應(yīng)的文件。

舉例:關(guān)于/dev/zero的內(nèi)存映射

共享內(nèi)存可以用于不相關(guān)的內(nèi)存之間九串,如果內(nèi)存之間是相關(guān)的绞佩,那么我們可使用其它的技術(shù)。

下面講述的方法可以用于FreeBSD 5.2.1, Linux 2.4.22, 和 Solaris 9猪钮,而Mac OS X 10.3目前不支持將字符設(shè)備映射到進(jìn)程地址空間品山。

設(shè)備/dev/zero在被讀取的時(shí)候會(huì)提供無(wú)限個(gè)0。這個(gè)設(shè)備也接收任何寫入到它的數(shù)據(jù)烤低,但是它會(huì)忽略數(shù)據(jù)肘交。我們?cè)贗PC中利用了它在內(nèi)存映射的時(shí)候的一個(gè)特性。

  • 一個(gè)匿名內(nèi)存區(qū)域?qū)?huì)被創(chuàng)建扑馁,它的大小為mmap的第2個(gè)參數(shù)涯呻,并且向上取整為最近的系統(tǒng)頁(yè)大小。
  • 內(nèi)存區(qū)域會(huì)被初始化為0腻要。
  • 如果一個(gè)祖先進(jìn)程指定了MAP_SHARED標(biāo)記的mmap那么多個(gè)進(jìn)程可以共享這個(gè)內(nèi)存區(qū)域复罐。

下面的程序展示了使用這個(gè)設(shè)備的方法。

#include <fcntl.h>
#include <sys/mman.h>
#define NLOOPS       1000
#define SIZE         sizeof(long)     /* 共享內(nèi)存區(qū)域大小 */

static int update(long *ptr)
{
    return((*ptr)++);    /* 返回增加之前的值 */
}

int main(void)
{
    int     fd, i, counter;
    pid_t   pid;
    void    *area;

    if ((fd = open("/dev/zero", O_RDWR)) < 0)
        err_sys("open error");
    if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
        err_sys("mmap error");
    close(fd);      /* 映射之后關(guān)閉/dev/zero */

    TELL_WAIT();

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {           /* 父進(jìn)程 */
        for (i = 0; i < NLOOPS; i += 2) {
            if ((counter = update((long *)area)) != i)
                err_quit("parent: expected %d, got %d", i, counter);

            TELL_CHILD(pid);
            WAIT_CHILD();
        }
    } else {                         /* 子進(jìn)程 */
        for (i = 1; i < NLOOPS + 1; i += 2) {
            WAIT_PARENT();

            if ((counter = update((long *)area)) != i)
                err_quit("child: expected %d, got %d", i, counter);

            TELL_PARENT(getppid());
        }
    }

    exit(0);
}

程序打開(kāi)一個(gè)/dev/zero設(shè)備闯第,然后調(diào)用mmap,指定了一個(gè)長(zhǎng)整數(shù)類型的大小缀拭。需要注意的是咳短,當(dāng)區(qū)域被映射的時(shí)候,我們可以關(guān)閉設(shè)備蛛淋。進(jìn)程然后創(chuàng)建一個(gè)子進(jìn)程咙好。因?yàn)闃?biāo)記MAP_SHARED已經(jīng)被指定,所以向內(nèi)存映射的區(qū)域?qū)懙膬?nèi)容會(huì)被其他的進(jìn)程看到褐荷。如果我們指定MAP_PRIVATE的話勾效,這個(gè)例子就不會(huì)工作了。

父子進(jìn)程然后交替運(yùn)行叛甫,使用前面的同步函數(shù)增加一個(gè)共享內(nèi)存區(qū)域的長(zhǎng)整數(shù)层宫。內(nèi)存映射區(qū)域被mmap初始化為0。父進(jìn)程把它增加到1其监,然后子進(jìn)程把它增加到2萌腿,然后父進(jìn)程把它增加到3,等等抖苦。

使用/dev/zero的方式毁菱,其優(yōu)點(diǎn)在于米死,在我們使用mmap創(chuàng)建映射的內(nèi)存區(qū)域的時(shí)候,實(shí)際的文件不需要存在贮庞。將/dev/zero映射會(huì)自動(dòng)創(chuàng)建一個(gè)指定大小的映射內(nèi)存區(qū)域峦筒。使用這個(gè)技術(shù)的缺點(diǎn)就是,它 只能工作在相關(guān)的進(jìn)程之間 窗慎∥锱纾可能使用線程會(huì)更加簡(jiǎn)單和高效。無(wú)論 使用什么方式捉邢,我們都必須使用同步的機(jī)制來(lái)控制訪問(wèn)的數(shù)據(jù) 脯丝。

匿名內(nèi)存映射的例子

許多實(shí)現(xiàn)提供匿名映射的功能,類似/dev/zero具有的特性伏伐。為了使用這個(gè)功能宠进,我們指定mmap的MAP_ANON標(biāo)記,并且指定文件描述符號(hào)為-1藐翎。返回的區(qū)域是匿名的(因?yàn)樗鼪](méi)有通過(guò)文件描述符號(hào)和任何一個(gè)路徑關(guān)聯(lián))材蹬,并且會(huì)創(chuàng)建一個(gè)可以 被子進(jìn)程共享的內(nèi)存映射區(qū)域

匿名內(nèi)存映射在本書的四個(gè)平臺(tái)上面都有支持吝镣。需要注意的是堤器,Linux為這個(gè)功能定義了MAP_ANONYMOUS標(biāo)記,但是為了便于程序的可移植特性末贾,定義MAP_ANON標(biāo)記為同樣的值闸溃。

我們可以做如下三個(gè)修改將前面的例子轉(zhuǎn)化成使用這個(gè)特性:

  1. 刪除將/dev/zero打開(kāi)的語(yǔ)句。

  2. 刪除將fd關(guān)閉的語(yǔ)句拱撵。

  3. 修改mmap的調(diào)用如下:

    if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
    

在這個(gè)調(diào)用中辉川,我們指定MAP_ANON標(biāo)記,并且設(shè)置文件描述符號(hào)為-1拴测。剩下的部分沒(méi)有變化乓旗。

總結(jié)

上面的最后兩例子,展示了在 相關(guān)的進(jìn)程之間進(jìn)行內(nèi)存的共享 集索。

如果 共享內(nèi)存在無(wú)關(guān)的進(jìn)程之間進(jìn)行 屿愚,那么有兩個(gè)可選的方法。

  1. 應(yīng)用程序可以使用XSI的共享內(nèi)存函數(shù)务荆,
  2. 或者他們可以使用帶有MAP_SHARED標(biāo)記的mmap函數(shù)妆距,將 同一個(gè)文件 映射到它們的地址空間。

譯者注

  1. 使用shmget函匕,獲得共享內(nèi)存標(biāo)識(shí)毅厚,共享內(nèi)存的數(shù)據(jù)結(jié)構(gòu)使用shmid_ds進(jìn)行表示。
  2. 使用shmctl浦箱,設(shè)置共享內(nèi)存的各個(gè)參數(shù)成員吸耿,以及初始化祠锣,獲取,刪除(只對(duì)標(biāo)識(shí)進(jìn)行刪除咽安,但是內(nèi)存在沒(méi)有使用的進(jìn)程之后才刪除)等伴网。
  3. 使用shmat,將共享內(nèi)存標(biāo)識(shí)進(jìn)行掛接(使用前)妆棒,返回相應(yīng)的內(nèi)存地址(會(huì)使得shmid_ds中相應(yīng)的計(jì)數(shù)增加)澡腾。
  4. 使用shmdt,將相應(yīng)地址的共享內(nèi)存進(jìn)行反掛接(不使用了)糕珊。
  5. 共享內(nèi)存屬于最快的IPC技術(shù)动分,因?yàn)樗愃苖map,不需要在進(jìn)程之間進(jìn)行數(shù)據(jù)的拷貝红选,與mmap不同的是共享內(nèi)存引用的不是文件澜公。

另外,mmap可以使用標(biāo)記MAP_ANON與fd=-1來(lái)實(shí)現(xiàn)匿名映射喇肋,這樣不需要打開(kāi)和關(guān)閉特定的文件路徑了坟乾,適用在父子進(jìn)程之間進(jìn)行通信。如果在無(wú)關(guān)進(jìn)程之間通信蝶防,則可以使用共享內(nèi)存或者將同一文件使用mmap映射到各自進(jìn)程的空間中甚侣。

  • int semget(key_t key, int nsems, int flag) 中,創(chuàng)建的是一個(gè)信號(hào)量集间学,而非單一信號(hào)量殷费。權(quán)限是集合的權(quán)限;集合中每個(gè)信號(hào)量都有特定的值低葫。
  • int semctl(int semid, int semnum, int cmd, ... /* union semun arg */) 中详羡, semnum表示是集合中的第 semnum 個(gè)信號(hào)量。
  • int semop(int semid, struct sembuf semoparray[], size_t nops) 中氮采,設(shè)置SEM_UNDO標(biāo)記并非改變信號(hào)操作殷绍,而是額外記錄一個(gè)調(diào)整值以備異常染苛。

記錄鎖性能不如信號(hào)量但是使用簡(jiǎn)單鹊漠。信號(hào)量每次創(chuàng)建一個(gè)信號(hào)量集合,而非單個(gè)信號(hào)量茶行,在某些場(chǎng)景比如:需要的資源不止一種的時(shí)候躯概,可能維護(hù)起來(lái)會(huì)相對(duì)方便,因?yàn)榧卸x資源到集合中了畔师,而非單獨(dú)各自定義娶靡。

原文參考

參考: APUE2/ch15lev1sec9.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市看锉,隨后出現(xiàn)的幾起案子姿锭,更是在濱河造成了極大的恐慌塔鳍,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呻此,死亡現(xiàn)場(chǎng)離奇詭異轮纫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)焚鲜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門掌唾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人忿磅,你說(shuō)我怎么就攤上這事糯彬。” “怎么了葱她?”我有些...
    開(kāi)封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵撩扒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我览效,道長(zhǎng)却舀,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任锤灿,我火速辦了婚禮挽拔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘但校。我一直安慰自己螃诅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布状囱。 她就那樣靜靜地躺著术裸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亭枷。 梳的紋絲不亂的頭發(fā)上袭艺,一...
    開(kāi)封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音叨粘,去河邊找鬼猾编。 笑死,一個(gè)胖子當(dāng)著我的面吹牛升敲,可吹牛的內(nèi)容都是我干的答倡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驴党,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瘪撇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤倔既,失蹤者是張志新(化名)和其女友劉穎恕曲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體渤涌,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡码俩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歼捏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稿存。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瞳秽,靈堂內(nèi)的尸體忽然破棺而出瓣履,到底是詐尸還是另有隱情,我是刑警寧澤练俐,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布袖迎,位于F島的核電站,受9級(jí)特大地震影響腺晾,放射性物質(zhì)發(fā)生泄漏燕锥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一悯蝉、第九天 我趴在偏房一處隱蔽的房頂上張望归形。 院中可真熱鬧,春花似錦鼻由、人聲如沸暇榴。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔼紧。三九已至,卻和暖如春狠轻,著一層夾襖步出監(jiān)牢的瞬間奸例,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工向楼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留查吊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓蜜自,卻偏偏與公主長(zhǎng)得像菩貌,于是被迫代替她去往敵國(guó)和親卢佣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子重荠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348