国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【linux 多線程并發(fā)】多線程模型下的信號(hào)通信處理,與多進(jìn)程處理的比較,屬于相同進(jìn)程的線程信號(hào)分發(fā)機(jī)制

這篇具有很好參考價(jià)值的文章主要介紹了【linux 多線程并發(fā)】多線程模型下的信號(hào)通信處理,與多進(jìn)程處理的比較,屬于相同進(jìn)程的線程信號(hào)分發(fā)機(jī)制。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

07線程信號(hào)處理

?專欄內(nèi)容

  • 參天引擎內(nèi)核架構(gòu)
    本專欄一起來聊聊參天引擎內(nèi)核架構(gòu),以及如何實(shí)現(xiàn)多機(jī)的數(shù)據(jù)庫節(jié)點(diǎn)的多讀多寫,與傳統(tǒng)主備,MPP的區(qū)別,技術(shù)難點(diǎn)的分析,數(shù)據(jù)元數(shù)據(jù)同步,多主節(jié)點(diǎn)的情況下對(duì)故障容災(zāi)的支持。

  • 手寫數(shù)據(jù)庫toadb
    本專欄主要介紹如何從零開發(fā),開發(fā)的步驟,以及開發(fā)過程中的涉及的原理,遇到的問題等,讓大家能跟上并且可以一起開發(fā),讓每個(gè)需要的人成為參與者。
    本專欄會(huì)定期更新,對(duì)應(yīng)的代碼也會(huì)定期更新,每個(gè)階段的代碼會(huì)打上tag,方便階段學(xué)習(xí)。

?開源貢獻(xiàn)

  • toadb開源庫

個(gè)人主頁:我的主頁
管理社區(qū):開源數(shù)據(jù)庫
座右銘:天行健,君子以自強(qiáng)不息;地勢坤,君子以厚德載物.

前言

現(xiàn)代的CPU都是多core處理器,而且在intel處理器中每個(gè)core又可以多個(gè)processor,形成了多任務(wù)并行處理的硬件架構(gòu),在服務(wù)器端的處理器上架構(gòu)又有一些不同,傳統(tǒng)的采用SMP,也就是對(duì)稱的多任務(wù)處理架構(gòu),每個(gè)任務(wù)都可以對(duì)等的訪問所有內(nèi)存,外設(shè)等,而如今在ARM系列CPU上,多采用NUMA架構(gòu),它將CPU核分了幾個(gè)組,給每個(gè)組的CPU core分配了對(duì)應(yīng)的內(nèi)存和外設(shè),CPU訪問對(duì)應(yīng)的內(nèi)存和外設(shè)時(shí)速度最優(yōu),跨組訪問時(shí)性能會(huì)降底一些。

隨著硬件技術(shù)的持續(xù)發(fā)展,它們對(duì)一般應(yīng)用的性能優(yōu)化能力越來越強(qiáng),同時(shí)對(duì)于服務(wù)器軟件的開發(fā),提出更高要求,要想達(dá)到極高的并發(fā)和性能,就需要充分利用當(dāng)前硬件架構(gòu)的特點(diǎn),對(duì)它們進(jìn)行壓榨。那么,我們的應(yīng)用至少也是要采用多任務(wù)架構(gòu),不管是多線程還是多進(jìn)程的多任務(wù)架構(gòu),才可以充分利用硬件的資源,達(dá)到高效的處理能力。

當(dāng)然多任務(wù)框架的采用,不僅僅是多線程的執(zhí)行,需要對(duì)多任務(wù)下帶來的問題進(jìn)行處理,如任務(wù)執(zhí)行返回值獲取,任務(wù)間數(shù)據(jù)的傳遞,任務(wù)執(zhí)行次序的協(xié)調(diào);當(dāng)然也不是任務(wù)越多處理越快,要避免線程過多導(dǎo)致操作系統(tǒng)夯住,也要防止任務(wù)空轉(zhuǎn)過快導(dǎo)致CPU使用率飆高。

本專欄主要介紹使用多線程與多進(jìn)程模型,如何搭建多任務(wù)的應(yīng)用框架,同時(shí)對(duì)多任務(wù)下的數(shù)據(jù)通信,數(shù)據(jù)同步,任務(wù)控制,以及CPU core與任務(wù)綁定等相關(guān)知識(shí)的分享,讓大家在實(shí)際開發(fā)中輕松構(gòu)建自已的多任務(wù)程序。

概述

信號(hào)是linux平臺(tái)下一個(gè)重要的并發(fā)通信方式,對(duì)于簡單的指令可以非常方便的通知到另外的并發(fā)任務(wù),同時(shí)利用了軟中斷的機(jī)制,讓信號(hào)的接收變得很高效。

我們知道信號(hào)一般針對(duì)的都是進(jìn)程,NTPL線程庫和C標(biāo)準(zhǔn)庫給我們提供了一些API,可以在線程級(jí)別發(fā)送和接收信號(hào),同時(shí)可以控制信號(hào)阻塞狀態(tài)。

線程級(jí)別的信號(hào)處理API分為以下幾類:

  • 線程信號(hào)阻塞狀態(tài)控制 pthread_sigmask
  • 線程信號(hào)發(fā)送 pthread_kill
  • 信號(hào)等待處理sigwait,sigtimedwait,sigwaitinfo

線程信號(hào)處理流程

信號(hào)從產(chǎn)生到處理掉,整個(gè)過程可能需要花費(fèi)很長時(shí)間,也可能非???,中間會(huì)經(jīng)過幾個(gè)過程:

  • 信號(hào)產(chǎn)生,也就是發(fā)送信號(hào)成功;
  • 信號(hào)投遞,也就是信號(hào)被傳遞給了信號(hào)接收者;
  • 信號(hào)等待處理,信號(hào)接收者將信號(hào)放入等待處理隊(duì)列;如果是非實(shí)時(shí)信號(hào),隊(duì)列中只有一個(gè)相同信號(hào),實(shí)時(shí)信號(hào)多個(gè)相同信號(hào)都會(huì)入隊(duì);如果接收者選擇忽略該信號(hào),則信號(hào)被丟棄;
  • 信號(hào)處理,接收者調(diào)用信號(hào)處理函數(shù)處理信號(hào);這里的信號(hào)處理函數(shù)可以是用戶設(shè)置的,也可以是系統(tǒng)默認(rèn)的;

在這幾個(gè)過程中,中間兩個(gè)過程認(rèn)為是信號(hào)未決,等待處理隊(duì)列可以認(rèn)為是未決隊(duì)列,當(dāng)我們阻塞某個(gè)信號(hào)時(shí),它就會(huì)一直在等待隊(duì)列中,直到信號(hào)阻塞狀態(tài)取消才會(huì)調(diào)用信號(hào)處理函數(shù)。

那么涉及信號(hào)處理的,就有三個(gè)內(nèi)容:

  • 信號(hào)掩碼
  • 信號(hào)未決隊(duì)列
  • 信號(hào)處理函數(shù)

下面我們來看一下進(jìn)程與線程信號(hào)處理流程,以及它們的不同點(diǎn)。

進(jìn)程信號(hào)的處理

進(jìn)程會(huì)有一個(gè)信號(hào)掩碼(屏蔽字,其中的信號(hào)會(huì)被阻塞)信號(hào)一般會(huì)先到達(dá)進(jìn)程,然后再分發(fā)到進(jìn)程所屬的線程,當(dāng)然分發(fā)給誰,這就很難確定。

信號(hào)未決隊(duì)列,進(jìn)程會(huì)有一個(gè),它里面會(huì)有所有到達(dá)的信號(hào);

信號(hào)處理函數(shù)的設(shè)置,也是進(jìn)程級(jí)別,也就是說信號(hào)處理函數(shù)只有一個(gè),不管那個(gè)線程修改了,進(jìn)程所屬的所有線程都會(huì)改變。

線程信號(hào)的處理

對(duì)于線程,它是好像是下級(jí)部門,指令下達(dá)就有點(diǎn)困難。
信號(hào)掩碼和信號(hào)未決隊(duì)列,這兩個(gè)每個(gè)線程都會(huì)有獨(dú)立的一份,各線程可以自己設(shè)置,默認(rèn)是從創(chuàng)建者線程繼承而來,在線程創(chuàng)建時(shí),被創(chuàng)建的線程的信號(hào)未決隊(duì)列會(huì)被初始化為空。

如前面所說,信號(hào)處理函數(shù)沒有線程獨(dú)立的。

線程的困難就來了,對(duì)于信號(hào)是否能收到,在進(jìn)程收到信號(hào)時(shí),會(huì)分發(fā)給不阻塞該信號(hào)的其中一個(gè)線程,不確定會(huì)發(fā)給那個(gè)線程,對(duì)于線程來講,難啊。

線程也有一個(gè)優(yōu)勢,就是獲取的信號(hào)未決隊(duì)列,是當(dāng)前線程的未決列表與進(jìn)程隊(duì)列的未決列表的并集。

線程級(jí)的信號(hào)處理,一般采用將它需要處理的信號(hào)阻塞住,進(jìn)程級(jí)的阻塞,這樣所有線程都不會(huì)處理該信號(hào),然后線程就可以從未決隊(duì)列檢查是否有自己想要的信號(hào)了。

信號(hào)阻塞掩碼設(shè)置

#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);

通過此函數(shù)可以設(shè)置線程的信號(hào)阻塞掩碼值,它與進(jìn)程信號(hào)設(shè)置函數(shù)sigprocmask功能和使用方法一樣,只是應(yīng)用對(duì)象不同,一個(gè)是多線程下的,后者是多進(jìn)程并發(fā)。

參數(shù)取值說明

how 的取值如下:

  • SIG_BLOCK , set 信號(hào)集為阻塞信號(hào),加入到原來的阻塞信號(hào)列表中,也就是增加set中的信號(hào)到阻塞信號(hào)列表中;
  • SIG_UNBLOCK , 在阻塞信號(hào)列表中移除set中設(shè)置的信號(hào),也就是將set中的信號(hào)解除阻塞;當(dāng)然對(duì)于當(dāng)前沒有阻塞的信號(hào),不能進(jìn)行解除阻塞;
  • SIG_SETMASK , 將阻塞信號(hào)列表替換為 set中的信號(hào)列表,也就是將阻塞信號(hào)列表設(shè)置為set中的信號(hào);

set 是當(dāng)前需要設(shè)置的信號(hào)列表;

oldset 返回舊的信號(hào)列表,可以為NULL,則不接收舊的信號(hào)列表;

而信號(hào)集的設(shè)置, 有一套函數(shù)如下案例中的sigemptyset 清空集合, sigaddset 添加信號(hào)到集合。

發(fā)送信號(hào)

向進(jìn)程發(fā)送信號(hào)的函數(shù)是kill,但是它會(huì)向進(jìn)程內(nèi)的所有線程都會(huì)發(fā)送信號(hào);

給某一指定線程發(fā)送信號(hào),在NPTL線程庫中定義了專門的函數(shù)。

#include <signal.h>
int pthread_kill(pthread_t thread, int sig);

參數(shù)也非常明確,線程的標(biāo)識(shí)符和需要發(fā)送的信號(hào)ID;

這里需要特別注意:

  • 只能向當(dāng)前線程所屬的進(jìn)程范圍內(nèi)的線程發(fā)送信號(hào),當(dāng)然包括自己
  • 線程必須是存在的,不存在時(shí)會(huì)有些未定義的行為

信號(hào)等待

等待信號(hào)集set中指定的信號(hào)到達(dá),這些信號(hào)需要所有線程設(shè)置為阻塞狀態(tài),在信號(hào)未決列表中的信號(hào)都會(huì)被檢測到,取出當(dāng)前線程需要檢測的信號(hào)。

#include <signal.h>
int sigwait(const sigset_t *restrict set, int *restrict sig);

int sigwaitinfo(const sigset_t *restrict set,
                       siginfo_t *_Nullable restrict info);

int sigtimedwait(const sigset_t *restrict set,
                       siginfo_t *_Nullable restrict info,
                       const struct timespec *restrict timeout);

這三個(gè)函數(shù)都是C標(biāo)準(zhǔn)庫提供,并不是NPTL線程庫提供的,所以它們的函數(shù)命名不帶pthread。

當(dāng)信號(hào)沒有到達(dá)時(shí),會(huì)處于阻塞狀態(tài);當(dāng)信號(hào)到達(dá)時(shí),第一個(gè)函數(shù)會(huì)返回信號(hào)數(shù)字值,而后兩個(gè)會(huì)返回信號(hào)的信號(hào)結(jié)構(gòu)siginfo_t;

與前兩個(gè)不同的時(shí),第三個(gè)函數(shù)可以指定超時(shí)時(shí)間,當(dāng)信號(hào)未到達(dá),又到了超時(shí)時(shí)間時(shí),返回錯(cuò)誤-1,此時(shí)errno為EAGAIN;

  • 參數(shù)說明

set ,信號(hào)信,設(shè)置了要等待的信號(hào);

代碼案例

通過一個(gè)例子來看一下。

/* 
 * created by senllang 2024/1/4 
 * mail : study@senllang.onaliyun.com 
 *
 * Copyright (c) 2023-2024 senllang

 * This is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * 
 */

#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void *
sig_thread(void *arg)
{
    sigset_t *set = arg;
    int s, sig;

    for (;;)
    {
        s = sigwait(set, &sig);
        if (s != 0)
            perror("sigwait");
        printf("Signal handling thread got signal %d\n", sig);

        if(sig == SIGQUIT)
            break;
    }
}

int main(int argc, char *argv[])
{
    pthread_t thread;
    sigset_t set;
    int s;
    void *res;

    /* Block SIGQUIT and SIGUSR1; other threads created by main()
       will inherit a copy of the signal mask. */

    sigemptyset(&set);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);
    s = pthread_sigmask(SIG_BLOCK, &set, NULL);
    if (s != 0)
        perror("pthread_sigmask");

    s = pthread_create(&thread, NULL, &sig_thread, &set);
    if (s != 0)
        perror("pthread_create");

    s = pthread_join(thread, &res);
    if (s != 0)
        perror( "pthread_join");

    return 0;    
}

這段程序?qū)⑿盘?hào)SIGQUITSIGUSR1添加到阻塞信號(hào)列表中,之后這兩個(gè)信號(hào)到達(dá)進(jìn)程時(shí)會(huì)被阻塞在信號(hào)隊(duì)列中,同時(shí)它創(chuàng)建的線程也會(huì)繼承這個(gè)信號(hào)掩碼。

阻塞信號(hào)的意思是,線程收到了,只是將它放入信號(hào)未決隊(duì)列中不調(diào)用處理函數(shù),為了檢測是否線程收到了這兩個(gè)信號(hào),我們?cè)谧泳€程中通過信號(hào)集進(jìn)行檢測,當(dāng)收到我們發(fā)出的信號(hào)時(shí)進(jìn)行打印,當(dāng)收到SIGQUIT時(shí),退出線程。

執(zhí)行結(jié)果如下:

[senllang@hatch example_07]$ gcc -lpthread threadSignalSetmask.c 
[senllang@hatch example_07]$ ./a.out &
[1] 2560005
[senllang@hatch example_07]$ kill -USR1 %1
Signal handling thread got signal 10
[senllang@hatch example_07]$ kill -USR1 %1
Signal handling thread got signal 10
[senllang@hatch example_07]$ kill -QUIT %1
Signal handling thread got signal 3
[1]+  Done                    ./a.out

可以看到主線程和子線程收到這兩個(gè)信號(hào)后,都沒有反應(yīng),被阻塞了,而我們的信號(hào)集檢測發(fā)現(xiàn)確實(shí)收到了這兩個(gè)信號(hào);
kill 命令是給進(jìn)程發(fā)達(dá)了信號(hào),該信號(hào)會(huì)給當(dāng)前進(jìn)程的所有線程都會(huì)發(fā)送相同信號(hào),所以主線程和子線程都會(huì)收到。

總結(jié)

在目前線程信號(hào)實(shí)現(xiàn)的機(jī)制下,多線程的信號(hào)處理,信號(hào)處理會(huì)在單獨(dú)的某個(gè)線程進(jìn)行。比如進(jìn)程退出時(shí),也是由進(jìn)程給每一個(gè)線程再發(fā)送退出信號(hào),多線程的實(shí)現(xiàn)方法與此類似。

在具有事件循環(huán)的應(yīng)用中,在信號(hào)的的 handler 中,可以將信號(hào)直接放入程序的隊(duì)列中,立刻返回。這樣直到線程從程序的隊(duì)列中取出這個(gè)信號(hào)為止,整個(gè)線程看起來就像沒有“中斷”。

本文所涉及的代碼已經(jīng)上傳到工程hatchCode, 在multipleThreads/example_07目錄下;

結(jié)尾

非常感謝大家的支持,在瀏覽的同時(shí)別忘了留下您寶貴的評(píng)論,如果覺得值得鼓勵(lì),請(qǐng)點(diǎn)贊,收藏,我會(huì)更加努力!

作者郵箱:study@senllang.onaliyun.com
如有錯(cuò)誤或者疏漏歡迎指出,互相學(xué)習(xí)。文章來源地址http://www.zghlxwxcb.cn/news/detail-796779.html

到了這里,關(guān)于【linux 多線程并發(fā)】多線程模型下的信號(hào)通信處理,與多進(jìn)程處理的比較,屬于相同進(jìn)程的線程信號(hào)分發(fā)機(jī)制的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包