實(shí)驗(yàn)三:進(jìn)程運(yùn)行軌跡的跟蹤與統(tǒng)計(jì)

實(shí)驗(yàn)要求

實(shí)驗(yàn)要求參考實(shí)驗(yàn)樓課程副渴。

實(shí)驗(yàn)?zāi)康?/h1>
  1. 掌握Linux下的多進(jìn)程編程技術(shù)翼悴;
  2. 通過(guò)對(duì)進(jìn)程運(yùn)行軌跡的跟蹤來(lái)形象化進(jìn)程的概念信卡;
  3. 在進(jìn)程運(yùn)行軌跡跟蹤的基礎(chǔ)上進(jìn)行相應(yīng)的數(shù)據(jù)統(tǒng)計(jì)隔缀,從而能對(duì)進(jìn)程調(diào)度算法進(jìn)行實(shí)際的量化評(píng)價(jià),更進(jìn)一步加深對(duì)調(diào)度和調(diào)度算法的理解坐求,獲得能在實(shí)際操作系統(tǒng)上對(duì)調(diào)度算法進(jìn)行實(shí)驗(yàn)數(shù)據(jù)對(duì)比的直接經(jīng)驗(yàn)蚕泽。

實(shí)驗(yàn)內(nèi)容

  1. 基于模板“process.c”編寫(xiě)多進(jìn)程的樣本程序晌梨,實(shí)現(xiàn)如下功能:所有子進(jìn)程都并行運(yùn)行桥嗤,每個(gè)子進(jìn)程的實(shí)際運(yùn)行時(shí)間一般不超過(guò)30秒;父進(jìn)程向標(biāo)準(zhǔn)輸出打印所有子進(jìn)程的id仔蝌,并在所有子進(jìn)程都退出后才退出泛领;
  2. 在Linux0.11上實(shí)現(xiàn)進(jìn)程運(yùn)行軌跡的跟蹤×簿基本任務(wù)是在內(nèi)核中維護(hù)一個(gè)日志文件/var/process.log渊鞋,把從操作系統(tǒng)啟動(dòng)到系統(tǒng)關(guān)機(jī)過(guò)程中所有進(jìn)程的運(yùn)行軌跡都記錄在這一log文件中。
  3. 在修改過(guò)的0.11上運(yùn)行樣本程序,通過(guò)分析log文件锡宋,統(tǒng)計(jì)該程序建立的所有進(jìn)程的等待時(shí)間儡湾、完成時(shí)間(周轉(zhuǎn)時(shí)間)和運(yùn)行時(shí)間,然后計(jì)算平均等待時(shí)間执俩,平均完成時(shí)間和吞吐量徐钠。可以自己編寫(xiě)統(tǒng)計(jì)程序役首,也可以使用python腳本程序——stat_log.py(hit-oslab/common/files)——進(jìn)行統(tǒng)計(jì)尝丐。
  4. 修改0.11進(jìn)程調(diào)度的時(shí)間片,然后再運(yùn)行同樣的樣本程序衡奥,統(tǒng)計(jì)同樣的時(shí)間數(shù)據(jù)爹袁,和原有的情況對(duì)比,體會(huì)不同時(shí)間片帶來(lái)的差異矮固。

實(shí)驗(yàn)步驟

process.c 代碼

在實(shí)現(xiàn)的process.c中失息,一共fork 了5個(gè)進(jìn)程。

int main(int argc, char * argv[])
{
    int pid, stat_addr;
    if (! (pid = fork())) {
        cpuio_bound(30, 1, 1);
    } else {
        printf("fork %d.\n", pid);
        if (! (pid = fork())) {
            cpuio_bound(30, 30, 0);
        } else {
            printf("fork %d.\n", pid);
            if (! (pid = fork())) {
                cpuio_bound(30, 0, 30);
            } else {
                printf("fork %d.\n", pid);
                if (! (pid = fork())) {
                    cpuio_bound(30, 9, 1);
                } else {
                    printf("fork %d.\n", pid);
                    if (! (pid = fork())) {
                        cpuio_bound(30, 1, 9);
                    } else {
                        printf("fork %d.\n", pid);
                    }
                }
            }
        }
    }
    wait(&stat_addr);
    return 0;
}

程序運(yùn)行軌跡的跟蹤

日志文件的格式

參考實(shí)驗(yàn)課程文檔乏屯。

打開(kāi)日志文件

同上根时。

寫(xiě)日志文件

同上。

尋找狀態(tài)切換點(diǎn)

關(guān)于進(jìn)程運(yùn)行狀態(tài)的綜述和狀態(tài)切換圖辰晕,可以參考《Linux內(nèi)核完全剖析:基于0.12內(nèi)核》:P175蛤迎。

進(jìn)程的新建(N)及由新建(N)切換到就緒(N)狀態(tài)

新建進(jìn)程是由fork()實(shí)現(xiàn)的,該函數(shù)在內(nèi)核中實(shí)現(xiàn)為sys_fork()含友。sys_fork()函數(shù)位于kernel/system_call.s: 208替裆。

sys_fork:
    call find_empty_process
    testl %eax,%eax
    js 1f
    push %gs
    pushl %esi
    pushl %edi
    pushl %ebp
    pushl %eax
    call copy_process
    addl $20,%esp
1:  ret

find_empty_process函數(shù)用于獲取系統(tǒng)中一個(gè)可用的pid,而copy_process函數(shù)負(fù)責(zé)創(chuàng)建一個(gè)子進(jìn)程窘问,并把父進(jìn)程的所有寄存器內(nèi)容直接復(fù)制給子進(jìn)程辆童。
copy_process位于kernel/fork.c: 68。

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
        long ebx,long ecx,long edx,
        long fs,long es,long ds,
        long eip,long cs,long eflags,long esp,long ss)
{
    struct task_struct *p;
    int i;
    struct file *f;

    p = (struct task_struct *) get_free_page();
    if (!p)
        return -EAGAIN;
    task[nr] = p;
    *p = *current;    /* NOTE! this doesn't copy the supervisor stack */
    p->state = TASK_UNINTERRUPTIBLE;
/* =========== modified =========== */
    fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'N', jiffies);
/* =========== modified =========== */
    p->pid = last_pid;
    p->father = current->pid;
    /* 省略若干代碼 */
    p->state = TASK_RUNNING;    /* do this last, just in case */
/* =========== modified =========== */
    fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);
/* =========== modified =========== */
    return last_pid;

copy_process函數(shù)實(shí)現(xiàn)的功能包括:

  1. 為新任務(wù)的task_struct分配內(nèi)存惠赫,并將當(dāng)前當(dāng)前任務(wù)的task_struct復(fù)制給新任務(wù)把鉴。
  2. 修改新任務(wù)的task_struct。此時(shí)儿咱。需要將新任務(wù)的狀態(tài)設(shè)置為不可中斷狀態(tài)庭砍,防止其被內(nèi)核調(diào)度執(zhí)行。筆者認(rèn)為混埠,此時(shí)新任務(wù)已經(jīng)完成了新建(N)狀態(tài)怠缸。
  3. 修改任務(wù)狀態(tài)段(TSS)數(shù)據(jù)。此時(shí)钳宪,需要設(shè)置TSS中的內(nèi)核棧信息(ss0:dsp0)揭北,將傳入函數(shù)的參數(shù)賦給TSS中對(duì)應(yīng)的寄存器扳炬,保存本任務(wù)的LDT描述符和狀態(tài)位圖。值得注意的是搔体,在設(shè)置寄存器時(shí)恨樟,需要將新任務(wù)的eax的值置為0,而對(duì)于父任務(wù)來(lái)說(shuō)疚俱,eax的值是find_empty_process函數(shù)的返回值厌杜。這也就是父進(jìn)程調(diào)用fork函數(shù)返回子進(jìn)程的ID,而子進(jìn)程調(diào)用fork函數(shù)返回0的原因计螺。
  4. 復(fù)制進(jìn)程頁(yè)表夯尽;處理文件引用數(shù);在GDT表中設(shè)置新任務(wù)是TSS段和LDT段描述符登馒;設(shè)置進(jìn)程之間的關(guān)系列表指針匙握。
  5. 將任務(wù)置為可運(yùn)行狀態(tài)。此時(shí)陈轿,新任務(wù)處于就緒(J)狀態(tài)圈纺。

進(jìn)程的就緒(J)狀態(tài)和運(yùn)行(R)狀態(tài)之間的切換

在linux-0.11的內(nèi)核代碼中是不區(qū)分就緒狀態(tài)和運(yùn)行狀態(tài)的,二者都是TASK_RUNNING麦射。所以代碼中并沒(méi)有顯示地對(duì)這兩種狀態(tài)切換的代碼蛾娶。
實(shí)現(xiàn)進(jìn)程切換的代碼是switch_to(int)(kernel/sched.c: 141)函數(shù)。在切換進(jìn)程之前的代碼實(shí)現(xiàn)了進(jìn)程調(diào)度的算法潜秋,這些將在下文中討論蛔琅。進(jìn)程調(diào)度算法按照一定的策略找到下個(gè)執(zhí)行的進(jìn)程的ID(next),使用switch_to函數(shù)將cpu的使用權(quán)交給next號(hào)進(jìn)程峻呛。需要注意的是罗售,next號(hào)進(jìn)程可能就是當(dāng)前正在執(zhí)行的進(jìn)程,所以首先要判斷next進(jìn)程是否是當(dāng)前進(jìn)程钩述。只有當(dāng)二者不相等時(shí)寨躁,才真正地發(fā)生了進(jìn)程的調(diào)度。next號(hào)進(jìn)程就由就緒狀態(tài)切換到運(yùn)行狀態(tài)牙勘。而如果當(dāng)前進(jìn)程是運(yùn)行狀態(tài)职恳,則其狀態(tài)需要切換到就緒態(tài)。
這里展開(kāi)分析一下方面,在linux-0.11的內(nèi)核中放钦,何時(shí)會(huì)將正在運(yùn)行的程序轉(zhuǎn)換成就緒狀態(tài)。在實(shí)驗(yàn)說(shuō)明文檔中有過(guò)說(shuō)明葡幸,對(duì)于linux-0.11系統(tǒng)來(lái)說(shuō)最筒,有一個(gè)長(zhǎng)度為10ms的tick贺氓。這個(gè)tick不僅僅是作為統(tǒng)計(jì)進(jìn)程的單位蔚叨,而且定時(shí)芯片(8253/8254)會(huì)每隔10ms向系統(tǒng)發(fā)出一次時(shí)間終端請(qǐng)求(int 0x20床蜘,時(shí)間中斷的代碼在kernel/sys_call.s: 176)。而系統(tǒng)在響應(yīng)時(shí)間中斷時(shí)蔑水,會(huì)調(diào)用do_timer(long gpl)函數(shù)(kernel/sched.c: 305)邢锯。如果當(dāng)前正在執(zhí)行的用戶進(jìn)程的時(shí)間片已經(jīng)用完(即GPL == 3,且current->count == 0)搀别,該函數(shù)會(huì)調(diào)用schedule()函數(shù)進(jìn)行進(jìn)程調(diào)度操作丹擎,則當(dāng)前程序很有可能被切換到就緒狀態(tài)。

/* =========== modified =========== */
    if (task[next] != current) {
        if (current->state == TASK_RUNNING) {
            fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);
        }
        fprintk(3, "%ld\t%c\t%ld\n", task[next]->pid, 'R', jiffies);
    }
/* =========== modified =========== */
    switch_to(next);

進(jìn)程由運(yùn)行(R)狀態(tài)切換到阻塞(W)狀態(tài)

當(dāng)一個(gè)進(jìn)程需要等待一個(gè)外部事件時(shí)歇父,就需要將自身的狀態(tài)由運(yùn)行態(tài)切換到阻塞態(tài)蒂培。常見(jiàn)的外部事件包括等待I/O和等待其他進(jìn)程的消息等。在內(nèi)核中榜苫,等待同一個(gè)資源的進(jìn)程隱式地構(gòu)成一個(gè)等待隊(duì)列护戳,采用后進(jìn)先出(FILO)的策略。等待隊(duì)列的數(shù)據(jù)結(jié)構(gòu)可以參考《Linux內(nèi)核完全剖析:基于0.12內(nèi)核》:P299垂睬。在linux-0.11的內(nèi)核代碼中將進(jìn)程切換至阻塞態(tài)的函數(shù)是sleep_on(kernel/sched.c: 151)和interruptible_sleep_on(kernel/sched.c: 167)媳荒。
這2個(gè)函數(shù)的作用就是將暫時(shí)無(wú)法運(yùn)行的進(jìn)程切換到阻塞態(tài),并將該進(jìn)程的task_struct添加到等待隊(duì)列中驹饺。之后钳枕,會(huì)調(diào)用schedule()函數(shù)將CPU分配給其他的進(jìn)程。當(dāng)進(jìn)程被喚醒而重新執(zhí)行時(shí)就會(huì)執(zhí)行schedule()之后的語(yǔ)句赏壹,并把比它早進(jìn)入等待隊(duì)列的一個(gè)進(jìn)程喚醒鱼炒,即從阻塞態(tài)切換到就緒態(tài)。
interruptible_sleep_on與sleep_on的功能基本類(lèi)似蝌借,只是在進(jìn)行調(diào)度之前田柔,把當(dāng)前任務(wù)設(shè)置成可中斷等待狀態(tài),并在本任務(wù)被喚醒后還需要判斷自己是否為等待隊(duì)列中的第一個(gè)任務(wù)骨望。如果不是硬爆,則需要將自己重新設(shè)置成可中斷等待狀態(tài),并執(zhí)行schedule()函數(shù)擎鸠,讓出CPU的執(zhí)行權(quán)缀磕。
下面展示的是打印process.log的語(yǔ)句。
在sleep_on中:

void sleep_on(struct task_struct **p)
{
    struct task_struct *tmp;

    if (!p)
        return;
    if (current == &(init_task.task))
        panic("task[0] trying to sleep");
    tmp = *p;
    *p = current;
    current->state = TASK_UNINTERRUPTIBLE;
/* =========== modified =========== */
    fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
/* =========== modified =========== */
    schedule();
    if (tmp) {
        tmp->state=0;
/* =========== modified =========== */
        fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
/* =========== modified =========== */
    }
}

在interruptible_sleep_on中

void interruptible_sleep_on(struct task_struct **p)
{
    struct task_struct *tmp;

    if (!p)
        return;
    if (current == &(init_task.task))
        panic("task[0] trying to sleep");
    tmp=*p;
    *p=current;
repeat: current->state = TASK_INTERRUPTIBLE;
/* =========== modified =========== */
    fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
/* =========== modified =========== */
    schedule();
    if (*p && *p != current) {
        (**p).state=0;
/* =========== modified =========== */
        fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
/* =========== modified =========== */
        goto repeat;
    }
    *p=NULL;
    if (tmp) {
        tmp->state=0;
/* =========== modified =========== */
        fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
/* =========== modified =========== */
    }
}

除了上述的2個(gè)函數(shù)可以實(shí)現(xiàn)將進(jìn)程從執(zhí)行狀態(tài)切換到阻塞狀態(tài)劣光,sys_pause()(kernel/sched.c: 144)和sys_waitpid(kernel/exit.c: 142)也可以做到袜蚕。
當(dāng)schedule函數(shù)發(fā)現(xiàn)系統(tǒng)中沒(méi)有可執(zhí)行的任務(wù)時(shí),就會(huì)切換到0號(hào)任務(wù)绢涡,而0號(hào)任務(wù)就會(huì)循環(huán)執(zhí)行sys_pause牲剃,將自己設(shè)置為可中斷的阻塞態(tài)。理論上雄可,該系統(tǒng)調(diào)用將導(dǎo)致進(jìn)程進(jìn)入睡眠狀態(tài)凿傅,直到收到一個(gè)用于終止進(jìn)程或者促使進(jìn)程調(diào)用的信號(hào)量缠犀。然而這些功能在0.11版本內(nèi)核中沒(méi)有沒(méi)實(shí)現(xiàn)。

int sys_pause(void)
{
    current->state = TASK_INTERRUPTIBLE;
/* =========== modified =========== */
    if (current->pid != 0) {
        fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
    }
/* =========== modified =========== */
    schedule();
    return 0;
}

而sys_waitpid函數(shù)的功能則是對(duì)任務(wù)數(shù)組進(jìn)行掃描聪舒,如果其中有子進(jìn)程不處于退出狀態(tài)或者僵死狀態(tài)辨液,則將父進(jìn)程切換到可中斷的阻塞狀態(tài)。

進(jìn)程由阻塞(W)狀態(tài)切換到就緒(J)狀態(tài)

將進(jìn)程由阻塞態(tài)切換到就緒態(tài)的函數(shù)箱残,除了之前小節(jié)中提到的sleep_on和interruptible_sleep_on函數(shù)滔迈,wake_up和schedule函數(shù)也能完成該切換。
wake_up函數(shù)直接將等待隊(duì)列中的第一個(gè)任務(wù)喚醒:

void wake_up(struct task_struct **p)
{
    if (p && *p) {
        (**p).state=0;
/* =========== modified =========== */
        fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
/* ========== modified =========== */
        *p=NULL;
    }
}

而在schedule函數(shù)中被辑,首先會(huì)檢測(cè)進(jìn)程的報(bào)警定時(shí)值(alarm)燎悍,并將處于可中斷狀態(tài)且接收到信號(hào)的進(jìn)程喚醒。

for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
    if (*p) {
        if ((*p)->alarm && (*p)->alarm < jiffies) {
                (*p)->signal |= (1<<(SIGALRM-1));
            (*p)->alarm = 0;
        }
        if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
        (*p)->state==TASK_INTERRUPTIBLE) {
            (*p)->state=TASK_RUNNING;
/* =========== modified =========== */
            fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
/* =========== modified =========== */
        }
    }
}

進(jìn)程的退出

進(jìn)程退出狀態(tài)的設(shè)置是在do_exit(kernel/exit.c: 102)中實(shí)現(xiàn)的盼理。
該函數(shù)釋放當(dāng)前進(jìn)程的代碼段和數(shù)據(jù)段所占的內(nèi)存頁(yè)间涵,執(zhí)行與文件系統(tǒng)相關(guān)的清理工作,最后將進(jìn)程狀態(tài)設(shè)置為僵死狀態(tài)榜揖,并給退出碼賦值勾哩。

進(jìn)程時(shí)間統(tǒng)計(jì)

由于process.c在運(yùn)行時(shí)會(huì)在終端上打印fork的子進(jìn)程編號(hào),在進(jìn)行時(shí)間統(tǒng)計(jì)時(shí)举哟,最好只統(tǒng)計(jì)這些進(jìn)程思劳。

chen@chen:oslab$ ./stat_log.py process.log 13 14 15 16 17
(Unit: tick)
Process   Turnaround   Waiting   CPU Burst   I/O Burst
     13         3158      1631         800         727
     14         3190      2125        1065           0
     15         3172        32           0        3139
     16         3171      2036        1019         115
     17         3144       610         300        2234
Average:     3167.00   1286.80
Throughout: 0.16/s

由上面的統(tǒng)計(jì)可以看出,處理器繁忙的進(jìn)程的等待時(shí)間也很長(zhǎng)妨猩,而I/O繁忙的進(jìn)程的等待時(shí)間會(huì)相對(duì)短一些潜叛。

調(diào)度算法修改

分析代碼可知,0.11的調(diào)度算法是選取counter值最大的就緒進(jìn)程進(jìn)行調(diào)度壶硅。其中運(yùn)行態(tài)進(jìn)程(即current)的counter數(shù)值會(huì)隨著時(shí)鐘中斷而不斷減1(時(shí)鐘中斷10ms一次)威兜,所以是一種比較典型的時(shí)間片輪轉(zhuǎn)調(diào)度算法。另外庐椒,由上面的程序可以看出椒舵,當(dāng)沒(méi)有counter值大于0的就緒進(jìn)程時(shí),要對(duì)所有的進(jìn)程做(*p)->counter = ((*p)->counter >> 1) + (*p)->priority约谈。其效果是對(duì)所有的進(jìn)程(包括阻塞態(tài)進(jìn)程)都進(jìn)行counter的衰減笔宿,并再累加priority值。這樣棱诱,對(duì)正被阻塞的進(jìn)程來(lái)說(shuō)泼橘,一個(gè)進(jìn)程在阻塞隊(duì)列中停留的時(shí)間越長(zhǎng),其優(yōu)先級(jí)越大迈勋,被分配的時(shí)間片也就會(huì)越大炬灭。所以總的來(lái)說(shuō),Linux 0.11的進(jìn)程調(diào)度是一種綜合考慮進(jìn)程優(yōu)先級(jí)并能動(dòng)態(tài)反饋調(diào)整時(shí)間片的輪轉(zhuǎn)調(diào)度算法靡菇。
時(shí)間片counter和優(yōu)先級(jí)priority的初始化在include/sched.h: 113重归。

#define INIT_TASK \ 
 { 0,15,15, //分別對(duì)應(yīng)state;counter;和priority;

只需要修改這個(gè)宏里的數(shù)字米愿,就可以修改counter和priority的初始值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末提前,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泳唠,更是在濱河造成了極大的恐慌狈网,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笨腥,死亡現(xiàn)場(chǎng)離奇詭異拓哺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)脖母,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)士鸥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谆级,你說(shuō)我怎么就攤上這事烤礁。” “怎么了肥照?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵脚仔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我舆绎,道長(zhǎng)鲤脏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任吕朵,我火速辦了婚禮猎醇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘努溃。我一直安慰自己硫嘶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布梧税。 她就那樣靜靜地躺著音半,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贡蓖。 梳的紋絲不亂的頭發(fā)上曹鸠,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音斥铺,去河邊找鬼彻桃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晾蜘,可吹牛的內(nèi)容都是我干的邻眷。 我是一名探鬼主播眠屎,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肆饶!你這毒婦竟也來(lái)了改衩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤驯镊,失蹤者是張志新(化名)和其女友劉穎葫督,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體板惑,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橄镜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冯乘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洽胶。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裆馒,靈堂內(nèi)的尸體忽然破棺而出姊氓,到底是詐尸還是另有隱情,我是刑警寧澤喷好,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布他膳,位于F島的核電站,受9級(jí)特大地震影響绒窑,放射性物質(zhì)發(fā)生泄漏棕孙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一些膨、第九天 我趴在偏房一處隱蔽的房頂上張望蟀俊。 院中可真熱鬧,春花似錦订雾、人聲如沸肢预。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烫映。三九已至,卻和暖如春噩峦,著一層夾襖步出監(jiān)牢的瞬間锭沟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工识补, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留族淮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像祝辣,于是被迫代替她去往敵國(guó)和親贴妻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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

  • 又來(lái)到了一個(gè)老生常談的問(wèn)題蝙斜,應(yīng)用層軟件開(kāi)發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢名惩? 今天就這個(gè)問(wèn)題開(kāi)始,來(lái)談?wù)劜?..
    tangsl閱讀 4,124評(píng)論 0 23
  • 轉(zhuǎn)自: http://www.reibang.com/p/486b0965c296 http://www.jia...
    demop閱讀 3,886評(píng)論 1 21
  • 進(jìn)程的描述與控制 1.前趨圖與程序執(zhí)行1.1 前趨圖介紹:描述程序先后執(zhí)行順序孕荠,又稱(chēng)為有向無(wú)循環(huán)圖娩鹉,可記為DAG(...
    孫夢(mèng)翔閱讀 702評(píng)論 0 1
  • 大家好,我是初一介紹作文家族的第二代:介紹家人岛琼。其實(shí)我并沒(méi)有大家想象的那么難底循,因?yàn)槲业膶?xiě)法要基于我家老大(自我介紹...
    馨雨仙子閱讀 534評(píng)論 0 0
  • 字符串 多行字符串 字符串模板 數(shù)組 擴(kuò)展 函數(shù)參數(shù)的擴(kuò)展 類(lèi)數(shù)組對(duì)象轉(zhuǎn)數(shù)組 函數(shù) 默認(rèn)值 以下兩種寫(xiě)法的區(qū)別? ...
    饑人谷_若愚閱讀 322評(píng)論 0 0