亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

大多數(shù)線程池實(shí)現(xiàn)都離不開鎖的使用,如互斥量pthread_mutex*結(jié)合條件變量pthread_cond*。眾所周知,鎖的使用對于程序性能影響較大,雖然現(xiàn)有的pthread_mutex*在鎖的申請與釋放方面做了較大的優(yōu)化,但是,線程池的實(shí)現(xiàn)是可以做到無鎖化的。

1.常見線程池實(shí)現(xiàn)原理

linux c編程之高效線程池如何實(shí)現(xiàn)無瑣化

 

如上圖所示,工作隊(duì)列由主線程和工作者線程共享,主線程將任務(wù)放進(jìn)工作隊(duì)列,工作者線程從工作隊(duì)列中取出任務(wù)執(zhí)行。共享工作隊(duì)列的操作需在互斥量的保護(hù)下安全進(jìn)行,主線程將任務(wù)放進(jìn)工作隊(duì)列時若檢測到當(dāng)前待執(zhí)行的工作數(shù)目小于工作者線程總數(shù),則需使用條件變量喚醒可能處于等待狀態(tài)的工作者線程。當(dāng)然,還有其他地方可能也會使用到互斥量和條件變量,不再贅述。

2.無鎖化線程池實(shí)現(xiàn)原理

linux c編程之高效線程池如何實(shí)現(xiàn)無瑣化

 

為解決無鎖化的問題,需要避免共享資源的競爭,因此將共享工作隊(duì)列加以拆分成每工作線程一個工作隊(duì)列的方式。對于主線程放入工作和工作線程取出任務(wù)的競爭問題,可以采取環(huán)形隊(duì)列的方式避免。在解決了鎖機(jī)制之后,就只剩下條件變量的問題了,條件變量本身即解決條件滿足時的線程通信問題,而信號作為一種通信方式,可以代替之,其大體編程范式為:

sigemptyset (&oldmask);
sigemptyset (&signal_mask);
sigaddset (&signal_mask, SIGUSR1);
rc = pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
if (rc != 0) {
    debug(TPOOL_ERROR, "SIG_BLOCK failed");
    return -1;
}
...

while (!condition) {
    rc = sigwait (&signal_mask, NULL);
    if (rc != 0) {
        debug(TPOOL_ERROR, "sigwait failed");
        return -1;
    }
}

rc = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
if (rc != 0) {
    debug(TPOOL_ERROR, "SIG_SETMASK failed");
    return -1;
}

需要C/C++ linux服務(wù)器架構(gòu)師學(xué)習(xí)資料私信“資料”(資料包括C/C++,Linux,golang技術(shù),Nginx,ZeroMQ,MySQL,redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK,ffmpeg等),免費(fèi)分享

linux c編程之高效線程池如何實(shí)現(xiàn)無瑣化

 

3.無鎖化線程池具體實(shí)現(xiàn)

在無鎖線程池中,區(qū)別于常見線程池的地方主要在于信號與條件變量、任務(wù)調(diào)度算法、增加或減少線程數(shù)目后的任務(wù)遷移,另外還有一點(diǎn)就是環(huán)形隊(duì)列的實(shí)現(xiàn)參考了Linux內(nèi)核中的kfifo實(shí)現(xiàn)。

(1) 信號與條件變量

信號與條件變量的區(qū)別主要在于條件變量的喚醒(signal)對于接收線程而言可以忽略,而在未設(shè)置信號處理函數(shù)的情況下信號的接收會導(dǎo)致接收線程甚至整個程序的終止,因此需要在線程池產(chǎn)生線程之前指定信號處理函數(shù),這樣新生的線程會繼承這個信號處理函數(shù)。多線程中信號的發(fā)送主要采用pthread_kill,為避免使用其他信號,本程序中使用了SIGUSR1。

(2) 任務(wù)調(diào)度算法

常見線程池實(shí)現(xiàn)的任務(wù)調(diào)度主要在操作系統(tǒng)一級通過線程調(diào)度實(shí)現(xiàn)。考慮到負(fù)載均衡,主線程放入任務(wù)時應(yīng)采取合適的任務(wù)調(diào)度算法將任務(wù)放入對應(yīng)的工作者線程隊(duì)列,本程序目前已實(shí)現(xiàn)Round-Robin和Least-Load算法。Round-Robin即輪詢式地分配工作,Least-Load即選擇當(dāng)前具有最少工作的工作者線程放入。

(3) 任務(wù)遷移

在線程的動態(tài)增加和減少的過程中,同樣基于負(fù)載均衡的考量,涉及到現(xiàn)有任務(wù)的遷移問題。負(fù)載均衡算法主要基于平均工作量的思想,即統(tǒng)計(jì)當(dāng)前時刻的總?cè)蝿?wù)數(shù)目,均分至每一個線程,求出每個工作者線程應(yīng)該增加或減少的工作數(shù)目,然后從頭至尾遍歷,需要移出工作的線程與需要移入工作的線程執(zhí)行任務(wù)遷移,相互抵消。最后若還有多出來的工作,再依次分配。遷入工作不存在競態(tài),因?yàn)榧尤牍ぷ魇冀K由主線程完成,而遷出工作則存在競態(tài),因?yàn)樵谶w出工作的同時工作者線程可能在同時執(zhí)行任務(wù)。所以需要采用原子操作加以修正,其主要思想即預(yù)取技術(shù),大致實(shí)現(xiàn)為:

do {
    work = NULL;
    if (thread_queue_len(thread) <= 0)  //also atomic
        break;
    tmp = thread->out;
    //prefetch work
    work = &thread->work_queue[queue_offset(tmp)];
} while (!__sync_bool_compare_and_swap(&thread->out, tmp, tmp + 1));
if (work) {
    // do something在線程的動態(tài)減少后,原先線程上未能執(zhí)行完的任務(wù)只需要由
    //主線程再次根據(jù)任務(wù)調(diào)度算法重新分配至其他存活的工作者線程隊(duì)列中即可,不
    //存在上述問題,當(dāng)然,此時可以同時執(zhí)行負(fù)載均衡算法加以優(yōu)化。
}

(4) 環(huán)形隊(duì)列

源碼中環(huán)形隊(duì)列實(shí)現(xiàn)主要參考了linux內(nèi)核中kfifo的實(shí)現(xiàn),如下圖所示:

linux c編程之高效線程池如何實(shí)現(xiàn)無瑣化

 

隊(duì)列長度為2的整次冪,out和in下標(biāo)一直遞增至越界后回轉(zhuǎn),其類型為unsigned int,即out指針一直追趕in指針,out和in映射至FiFo的對應(yīng)下標(biāo)處,其間的元素即為隊(duì)列元素。

分享到:
標(biāo)簽:線程
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定