RunLoop

概念

RunLoop事件接收分發(fā)機(jī)制的一個(gè)實(shí)現(xiàn),是線程相關(guān)的基礎(chǔ)框架的一部分氮双,一個(gè)RunLoop就是一個(gè)事件處理的循環(huán)碰酝,用來(lái)不停的調(diào)度工作以及處理輸入事件。

RunLoop本質(zhì)是一個(gè)do-while循環(huán)戴差,沒(méi)事做就休息送爸,來(lái)活了就干活。與普通的while循環(huán)是有區(qū)別的暖释,普通的while循環(huán)會(huì)導(dǎo)致CPU進(jìn)入忙等待狀態(tài)袭厂,即一直消耗cpu,而RunLoop則不會(huì)球匕,RunLoop是一種閑等待纹磺,即RunLoop具備休眠功能

RunLoop的作用
  • 保持程序的持續(xù)運(yùn)行
  • 處理APP中的各種事件(觸摸谐丢、定時(shí)器爽航、performSelector)
  • 節(jié)省cpu資源、提供程序的性能:該做事就做事乾忱,該休息就休息

RunLoop源碼的下載地址

RunLoop和線程的關(guān)系

首先,iOS 開(kāi)發(fā)中能遇到兩個(gè)線程對(duì)象:pthread_tNSThread历极,兩者是一一對(duì)應(yīng)的窄瘟,可以通過(guò)pthread_main_thread_np()[NSThread mainThread]來(lái)獲取主線程;也可以通過(guò) pthread_self()[NSThread currentThread]來(lái)獲取當(dāng)前線程趟卸。CFRunLoop是基于pthread來(lái)管理的蹄葱。
蘋(píng)果不允許直接創(chuàng)建 RunLoop,它只提供了兩個(gè)自動(dòng)獲取的函數(shù):CFRunLoopGetMain()CFRunLoopGetCurrent()锄列。

// 主運(yùn)行循環(huán)
 CFRunLoopRef mainRunloop = CFRunLoopGetMain();
 // 當(dāng)前運(yùn)行循環(huán)
 CFRunLoopRef currentRunloop = CFRunLoopGetCurrent();

/********** CFRunLoopGetMain ********/
CFRunLoopRef CFRunLoopGetMain(void) {
    CHECK_FOR_FORK();
    static CFRunLoopRef __main = NULL; // no retain needed
    //pthread_main_thread_np 主線程
    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
    return __main;
}

// 保存RunLoop的全局字典图云,key 是 pthread_t, value 是 CFRunLoopRef
static CFMutableDictionaryRef __CFRunLoops = NULL;
/*********_CFRunLoopGet0 *******/

// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    //如果t不存在邻邮,則標(biāo)記為主線程(即默認(rèn)情況竣况,默認(rèn)是主線程)
    if (pthread_equal(t, kNilPthreadT)) {
        t = pthread_main_thread_np();
    }
    __CFSpinLock(&loopsLock);
    if (!__CFRunLoops) {
        __CFSpinUnlock(&loopsLock);
        // 第一次進(jìn)入時(shí),初始化全局Dic筒严,并先為主線程創(chuàng)建一個(gè) RunLoop丹泉。
        //創(chuàng)建全局字典情萤,標(biāo)記為kCFAllocatorSystemDefault
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
        //通過(guò)主線程 創(chuàng)建主運(yùn)行循環(huán)
        CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
        //利用dict,進(jìn)行key-value綁定操作摹恨,即可以說(shuō)明筋岛,線程和runloop是一一對(duì)應(yīng)的
        // dict : key value
        CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
        
        if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
            CFRelease(dict);
        }
        
        CFRelease(mainLoop);
        __CFSpinLock(&loopsLock);
    }
    //通過(guò)其他線程獲取runloop
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    __CFSpinUnlock(&loopsLock);
    if (!loop) {
        //如果沒(méi)有獲取到,則新建一個(gè)運(yùn)行循環(huán)(所以子線程不獲取就不創(chuàng)建RunLoop)
        CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFSpinLock(&loopsLock);
        loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
        if (!loop) {
            //將新建的runloop 與 線程進(jìn)行key-value綁定
            CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
            loop = newLoop;
        }
        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
        __CFSpinUnlock(&loopsLock);
        CFRelease(newLoop);
    }
    if (pthread_equal(t, pthread_self())) {
        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
// 注冊(cè)一個(gè)回調(diào)晒哄,當(dāng)線程銷(xiāo)毀時(shí)睁宰,順便也銷(xiāo)毀其對(duì)應(yīng)的 RunLoop。
            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
        }
    }
    return loop;
}

從上面的代碼可以看出

  • Runloop只有兩種寝凌,一種是主線程的勋陪, 一個(gè)是其他線程
  • 線程RunLoop 之間是一一對(duì)應(yīng)的,其關(guān)系是保存在一個(gè)全局的 Dictionary里硫兰。
  • 主線程RunLoop已經(jīng)自動(dòng)獲茸缬蕖(創(chuàng)建)子線程默認(rèn)沒(méi)有開(kāi)啟RunLoop

RunLoop的創(chuàng)建

根據(jù)CFRunLoopRef的定義得知RunLoop為一個(gè)對(duì)象劫映,通過(guò)__CFRunLoop結(jié)構(gòu)體進(jìn)行創(chuàng)建

typedef struct __CFRunLoop * CFRunLoopRef;

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;            /* locked for accessing mode list */
    __CFPort _wakeUpPort;            // used for CFRunLoopWakeUp
    Boolean _unused;
    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
    pthread_t _pthread; // runloop和線程是一一對(duì)應(yīng)關(guān)系违孝,每個(gè)runloop內(nèi)部會(huì)保留一個(gè)對(duì)應(yīng)的線程
    uint32_t _winthread;
    CFMutableSetRef _commonModes;//標(biāo)記為common的mode的集合
    CFMutableSetRef _commonModeItems;//commonMode的item集合
    CFRunLoopModeRef _currentMode;// 當(dāng)前的模式
    CFMutableSetRef _modes;// CFRunLoopModeRef類(lèi)型的集合,相對(duì)NSArray有序泳赋,Set為無(wú)序集合
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};

/**********  __CFRunLoopMode *************/
struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;  /* must have the run loop locked before locking this */
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;

};

截屏2022-03-03 上午10.24.55.png

根據(jù)__CFRunLoop__CFRunLoopMode結(jié)構(gòu)體屬性可以看出雌桑,每個(gè)RunLoop中包含了多個(gè)ModeMode里面又包含了多個(gè)Source/Observer/Timer祖今,其中source分為source0source1校坑, 多個(gè)mode里,有且僅有一個(gè)currentMode千诬。如果要切換Mode耍目,只能退出當(dāng)前 Loop,再重新指定一個(gè)Mode進(jìn)入徐绑。這樣做主要是為了分隔開(kāi)不同組的 Source/Timer/Observer邪驮,讓其互不影響
截屏2022-03-03 上午10.24.09.png

ModeItem

Source & Timer & Observer統(tǒng)稱(chēng)為item傲茄,一個(gè)item可以被同時(shí)加入多個(gè)mode毅访。但一個(gè) item被重復(fù)加入同一個(gè) mode時(shí)是不會(huì)有效果的。如果一個(gè)mode一個(gè)item 都沒(méi)有盘榨,則RunLoop會(huì)直接退出喻粹,不進(jìn)入循環(huán)

  • Source表示可以喚醒RunLoop的一些事件,基于CFRunLoopSourceRef草巡,是事件產(chǎn)生的地方守呜,分為source0source1

    • source0:表示非系統(tǒng)事件,即用戶(hù)自定義的事件,只包含了一個(gè)回調(diào) 弛饭,它并不能主動(dòng)觸發(fā)事件冕末。使用時(shí),你需要先調(diào)用 CFRunLoopSourceSignal(source)侣颂,將這個(gè)Source標(biāo)記為待處理档桃,然后手動(dòng)調(diào)用CFRunLoopWakeUp(runloop)來(lái)喚醒RunLoop,讓其處理這個(gè)事件憔晒。
    • source1:表示系統(tǒng)事件藻肄,主要負(fù)責(zé)底層的通訊具備喚醒能力拒担,包含了一個(gè) mach_port一個(gè)回調(diào) 嘹屯,被用于通過(guò)內(nèi)核和其他線程相互發(fā)送消息。這種Source主動(dòng)喚醒RunLoop 的線程从撼。
  • Timer:就是常用NSTimer定時(shí)器這一類(lèi)州弟,基于CFRunLoopTimerRef,是基于時(shí)間的觸發(fā)器低零,它和NSTimertoll-free bridged的婆翔,可以混用。其包含一個(gè)時(shí)間長(zhǎng)度一個(gè)回調(diào)(函數(shù)指針)掏婶。當(dāng)其加入到 RunLoop 時(shí)啃奴,RunLoop會(huì)注冊(cè)對(duì)應(yīng)的時(shí)間點(diǎn),當(dāng)時(shí)間點(diǎn)到時(shí)雄妥,RunLoop會(huì)被喚醒以執(zhí)行那個(gè)回調(diào)最蕾。

struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits; //標(biāo)記fire狀態(tài)
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop; //添加該timer的runloop
    CFMutableSetRef _rlModes; //存放所有 包含該timer的 mode的 modeName,意味著一個(gè)timer可能會(huì)在多個(gè)mode中存在
    CFAbsoluteTime _nextFireDate; // 下一次觸發(fā)時(shí)間
    CFTimeInterval _interval;    //執(zhí)行的時(shí)間間隔
    CFTimeInterval _tolerance;   //時(shí)間偏差
    uint64_t _fireTSR;      // 觸發(fā)時(shí)間
    CFIndex _order;         /* immutable */
    CFRunLoopTimerCallBack _callout;    // 回調(diào)
    CFRunLoopTimerContext _context;  // 回調(diào)內(nèi)容
};
  • Observer: 主要用于監(jiān)聽(tīng)RunLoop的狀態(tài)變化老厌,并作出一定響應(yīng)瘟则,基于CFRunLoopObserverRef,是觀察者梅桩,結(jié)構(gòu)體內(nèi)部包含著一個(gè)_runloop成員壹粟, 表明每個(gè)Observer同時(shí)只能監(jiān)聽(tīng)一個(gè)RunLoop, 每個(gè) Observer 都包含了一個(gè)回調(diào),當(dāng) RunLoop狀態(tài)發(fā)生變化時(shí)宿百,觀察者就能通過(guò)回調(diào)接受到這個(gè)變化,主要有這幾個(gè)狀態(tài):
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    //進(jìn)入RunLoop
    kCFRunLoopEntry = (1UL << 0),
    //即將處理Timers
    kCFRunLoopBeforeTimers = (1UL << 1),
    //即將處理Source
    kCFRunLoopBeforeSources = (1UL << 2),
    //即將進(jìn)入休眠
    kCFRunLoopBeforeWaiting = (1UL << 5),
    //被喚醒
    kCFRunLoopAfterWaiting = (1UL << 6),
    //退出RunLoop
    kCFRunLoopExit = (1UL << 7),
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};
  • Item類(lèi)型
    • block應(yīng)用:__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__

    • 調(diào)用timer:__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__

    • 響應(yīng)source0: __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__

    • 響應(yīng)source1: __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__

    • GCD主隊(duì)列:__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__

    • observer源: __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__

可以根據(jù)蘋(píng)果官方文檔針對(duì)RunLoop處理不同源的圖示

截屏2022-03-03 上午10.56.49.png

  • 管理item接口
CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);
CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);

Timer為例

void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
    __CFRunLoopLock(rl);
    
    // 重點(diǎn) : kCFRunLoopCommonModes
    if (modeName == kCFRunLoopCommonModes) {
        //如果是kCFRunLoopCommonModes 類(lèi)型
       
        CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
        
        if (NULL == rl->_commonModeItems) {
            rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
        }
        //runloop與mode 是一對(duì)多的洪添, mode與item也是一對(duì)多的
        CFSetAddValue(rl->_commonModeItems, rlt);
        if (NULL != set) {
            CFTypeRef context[2] = {rl, rlt};
            /* add new item to all common-modes */
            //執(zhí)行
            CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
            CFRelease(set);
        }
    } else {
        //如果是非commonMode類(lèi)型
        //查找runloop的模型
        CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
        if (NULL != rlm) {
            if (NULL == rlm->_timers) {
                CFArrayCallBacks cb = kCFTypeArrayCallBacks;
                cb.equal = NULL;
                rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
            }
        }
        //判斷mode是否匹配
        if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
            __CFRunLoopTimerLock(rlt);
            if (NULL == rlt->_runLoop) {
                rlt->_runLoop = rl;
            } else if (rl != rlt->_runLoop) {
                __CFRunLoopTimerUnlock(rlt);
                __CFRunLoopModeUnlock(rlm);
                __CFRunLoopUnlock(rl);
                return;
            }
            // 如果匹配垦页,則將runloop加進(jìn)去,而runloop的執(zhí)行依賴(lài)于  [runloop run]
            CFSetAddValue(rlt->_rlModes, rlm->_name);
            __CFRunLoopTimerUnlock(rlt);
            __CFRunLoopTimerFireTSRLock();
            __CFRepositionTimerInMode(rlm, rlt, false);
            __CFRunLoopTimerFireTSRUnlock();
            if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
                // Normally we don't do this on behalf of clients, but for
                // backwards compatibility due to the change in timer handling...
                if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
            }
        }
        if (NULL != rlm) {
            __CFRunLoopModeUnlock(rlm);
        }
    }
   
    __CFRunLoopUnlock(rl);
}

RunLoop 執(zhí)行流程

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */

    // 通知Observers干奢, 進(jìn)入RunLoop
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
    // RunLoop里面具體要做的事情痊焊, 主要是一個(gè)循環(huán)
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
    // 通知Observers, 退出 RunLoop
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

    return result;
}

  
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
    
    
    mach_port_name_t dispatchPort = MACH_PORT_NULL;
 
    // 當(dāng)前是否為主線程
    bool cond1 = pthread_main_np();
    // _CFGetTSD(__CFTSDKeyIsInGCDMainQ) 從預(yù)先分配的插槽中獲取主線程的一些特定數(shù)據(jù)
    // CF源碼中沒(méi)有搜索到_CFSetTSD(__CFTSDKeyIsInGCDMainQ)的調(diào)用,推測(cè)但不完全確定_CFGetTSD(__CFTSDKeyIsInGCDMainQ) 為空
    bool cond2 = 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ);
    // 當(dāng)前是否為主線程
    bool cond3 = CFRunLoopGetMain() == rl;
    // 當(dāng)前的mode包含在commonModes里面
    bool cond4 = CFSetContainsValue(rl->_commonModes, rlm->_name);
 
    // 當(dāng)前為主線程且mode被標(biāo)記為common,dispatchPort才會(huì)被賦值
    if (cond1 && cond2 && cond3 && cond4) {
        dispatchPort = _dispatch_get_main_queue_port_4CF();
    }

 
    Boolean didDispatchPortLastTime = true;

    int32_t retVal = 0;
    do {

        __CFRunLoopUnsetIgnoreWakeUps(rl);

        // 通知observers薄啥, 即將處理Timers
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
        // 通知observers辕羽, 即將處理Sources
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
        // 處理Blocks
        __CFRunLoopDoBlocks(rl, rlm);

        // 處理source0
        if (__CFRunLoopDoSources0(rl, rlm, stopAfterHandle)) {
            // 處理Blocks
            __CFRunLoopDoBlocks(rl, rlm);
        }

        // timeout 傳入0 表示立即返回 傳入TIMEOUT_INFINITY 表示等待到消息再返回
        
        // 當(dāng)前為主線程且mode被標(biāo)記為common,且非第一次循環(huán)
        if (dispatchPort && !didDispatchPortLastTime) {
            // 主線程里有消息處理,直接跳轉(zhuǎn)到handle_msg
            if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
                goto handle_msg;
            }
        }
        didDispatchPortLastTime = false;
 
        // 通知observers垄惧, 即將進(jìn)入休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        __CFRunLoopSetSleeping(rl);

        // 線程進(jìn)入休眠刁愿,等待喚醒
        __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);

        __CFRunLoopUnsetSleeping(rl);
        // 通知observers, 已經(jīng)結(jié)束休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);

        // 處理消息
        handle_msg:;

        if (msg_is_timer) {
            // 處理timer
            __CFRunLoopDoTimers(rl, rlm, mach_absolute_time())
        } else if (msg_is_dispatch) {
            // 處理GCD  如果有dispatch到main_queue的block到逊,執(zhí)行block
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
        } else {
            // 處理Source1
            __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)
 
        }
 
        // 處理Blocks
        __CFRunLoopDoBlocks(rl, rlm);
        

          // 設(shè)置返回值
       if (sourceHandledThisLoop && stopAfterHandle) {
          //stopAfterHandle 是傳入的標(biāo)記铣口,如果處理完事件就返回
          retVal = kCFRunLoopRunHandledSource;
       } else if (timeout_context->termTSR < mach_absolute_time()) {
           //設(shè)置了超時(shí)時(shí)間,超時(shí)返回
          retVal = kCFRunLoopRunTimedOut;
       } else if (__CFRunLoopIsStopped(rl)) {
            // 被外部調(diào)用者強(qiáng)制停止了
          __CFRunLoopUnsetStopped(rl);
         retVal = kCFRunLoopRunStopped;
       } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
          // 內(nèi)部source,observers,timers 都空了觉壶,返回
          retVal = kCFRunLoopRunFinished;
       }
        
    // 如果不進(jìn)入上述的條件,繼續(xù)循環(huán)
    } while (0 == retVal);

    if (timeout_timer) {
        dispatch_source_cancel(timeout_timer);
        dispatch_release(timeout_timer);
    } else {
        free(timeout_context);
    }

    return retVal;
}

截屏2022-03-03 上午10.54.43.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脑题,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铜靶,更是在濱河造成了極大的恐慌叔遂,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件争剿,死亡現(xiàn)場(chǎng)離奇詭異已艰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)秒梅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)旗芬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人捆蜀,你說(shuō)我怎么就攤上這事疮丛。” “怎么了辆它?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵誊薄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我锰茉,道長(zhǎng)呢蔫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任飒筑,我火速辦了婚禮片吊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘协屡。我一直安慰自己俏脊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布肤晓。 她就那樣靜靜地躺著熙揍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灾搏。 梳的紋絲不亂的頭發(fā)上敢订,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛毕骡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窑睁,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼挺峡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了担钮?” 一聲冷哼從身側(cè)響起橱赠,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎箫津,沒(méi)想到半個(gè)月后狭姨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苏遥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年饼拍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片田炭。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡师抄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出教硫,到底是詐尸還是另有隱情叨吮,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布瞬矩,位于F島的核電站茶鉴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏景用。R本人自食惡果不足惜涵叮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伞插。 院中可真熱鬧割粮,春花似錦、人聲如沸媚污。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杠步。三九已至氢伟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幽歼,已是汗流浹背朵锣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甸私,地道東北人诚些。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像皇型,于是被迫代替她去往敵國(guó)和親诬烹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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