Linux: 信號【阻塞和捕捉信號】

Linux: 信號【阻塞和捕捉信號】

  • (一)阻塞信號
    • 1.信號其他相關的概念
    • 2.在內核中表示
    • 3.sigset_t
    • 4.信號集操作函數
    • 5.sigprocmask(設置阻塞)
    • 6.sigpending(得到未決狀態)
  • (二)捕捉信號
    • 1、內核空間與用戶空間
    • 2、內核態與用戶態
      • 2.1 內核如何實現信號的捕捉
    • 3.捕捉信號
      • signal函數
      • sigaction函數
    • 3.可重入函數
    • 4.volatile關鍵字
    • 5.SIGCHLD信號

(一)阻塞信號

1.信號其他相關的概念

  • 實際執行信號的處理動作,稱為信號遞達(Delivery)
  • 信號從產生到遞達之間的狀態,稱為信號未決(pending)
  • 進程可以選擇阻塞(Block) 某個信號。
  • 被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。
  • 需要注意的是,阻塞和忽略是不同的,只要信號被阻塞就不會遞達,而忽略是在遞達之后的一種處理動作

信號 傳遞過程:信號產生 -> 信號未決 -> 信號遞達
在這里插入圖片描述

2.在內核中表示

在這里插入圖片描述

  • 每個信號都有兩個標志位分別表示阻塞(block)和未決(pending),還有一個函數指針表示處理動作。信號產生時,內核在進程控制塊中設置該信號的未決標志,直到信號遞達才清除該標志。在上圖中,SIGHUP信號未阻塞也未產生過,當它遞達時執行默認處理動作。
  • SIGINT信號產生過,但正在被阻塞,所以暫時不能遞達。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因為進程仍有機會在改變處理動作之后再接觸阻塞。
  • SIGQUIT信號未產生過,但一旦產生SIGQUIT信號,該信號將被阻塞,它的處理動作是用戶自定義函數sighandler。如果在進程解除對某信號的阻塞之前,這種信號產生過多次,POSIX.1允許系統遞達該信號一次或多次。Linux是這樣實現的:普通信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列里,這里只討論普通信號。

block和pending都是用位圖表示,而handler是一個函數指針數組

  • 在block位圖中,比特位的位置代表某一個信號,比特位的內容代表該信號是否被阻塞。
  • 在pending位圖中,比特位的位置代表某一個信號,比特位的內容代表是否收到該信號。
  • handler表本質上是一個函數指針數組,數組的下標代表某一個信號,數組的內容代表該信號遞達時的處理動作,處理動作包括默認、忽略以及自定義
  • block、pending和handler這三張表的每一個位置是一一對應的。

3.sigset_t

從上圖來看,每個信號只有一個bit的未決標志,非0即1,不記錄該信號產生了多少次,阻塞標志也是這樣表示的。

因此,未決和阻塞標志可以用相同的數據類型sigset_t來存儲,sigset_t稱為信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處于未決狀態。

阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這里的“屏蔽”應該理解為阻塞而不是忽略。

#define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;typedef __sigset_t sigset_t;

_SIGSET_NWORDS 大小為 32,所以這是一個可以包含 32 個 無符號長整型 的數組,而每個 無符號長整型 大小為 4 字節,即 32 比特,至多可以使用 1024 個比特位

4.信號集操作函數

sigset_t類型對于每種信號用一個bit表示“有效”或“無效”,至于這個類型內部如何存儲這些bit則依賴于系統的實現,從使用者的角度是不必關心的,使用者只能調用以下函數來操作sigset_t變量,而不應該對它的內部數據做任何解釋。

#include <signal.h>int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set, int signum);int sigdelset(sigset_t *set, int signum);int sigismember(const sigset_t *set, int signum);  
  • sigemptyset函數:初始化set所指向的信號集,使其中所有信號的對應bit清零,表示該信號集不包含任何有效信號。
  • sigfillset函數:初始化set所指向的信號集,使其中所有信號的對應bit置位,表示該信號集的有效信號包括系統支持的所有信號。
  • sigaddset函數:在set所指向的信號集中添加某種有效信號。
  • sigdelset函數:在set所指向的信號集中刪除某種有效信號。
  • sigemptyset、sigfillset、sigaddset和sigdelset函數都是成功返回0,出錯返回-1。
  • sigismember是一個布爾函數,用于判斷一個信號集的有效信號中是否包含
    某種 信號,若包含則返回1,不包含則返回0,出錯返回-1。

5.sigprocmask(設置阻塞)

sigprocmask函數可以用于讀取或更改進程的信號屏蔽字(阻塞信號集),該函數的函數原型如下:

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

函數說明:

  • 參數how:
    在這里插入圖片描述
  • 參數set:
    就是一個信號集,主要從此信號集中獲取屏蔽信號信息
  • 參數oldset:
    一個信號集,保存進程中原來的 block 表

返回值:

  • sigprocmask函數調用成功返回0,出錯返回-1。
  • 如果調用sigprocmask解除了對當前若干個未決信號的阻塞,則在sigprocmask函數返回前,至少將其中一個信號遞達。

6.sigpending(得到未決狀態)

sigpending函數可以用于讀取進程的未決信號集,該函數的函數原型如下:
在這里插入圖片描述
sigpending函數讀取當前進程的未決信號集,并通過set參數傳出。該函數調用成功返回0,出錯返回-1。

(二)捕捉信號

1、內核空間與用戶空間

每一個進程都有自己的進程地址空間,該進程地址空間由內核空間和用戶空間組成:

  • 用戶所寫的代碼和數據位于用戶空間,通過用戶級頁表與物理內存之間建立映射關系。
  • 內核空間存儲的實際上是操作系統代碼和數據,通過內核級頁表與物理內存之間建立映射關系。

內核級頁表是一個全局的頁表,它用來維護操作系統的代碼與進程之間的關系。因此,在每個進程的進程地址空間中,用戶空間是屬于當前進程的,每個進程看到的代碼和數據是完全不同的,但內核空間所存放的都是操作系統的代碼和數據,所有進程看到的都是一樣的內容。
在這里插入圖片描述
內核級頁表只有一個并且是全部進程共享。而用戶級頁表有多個,每個進程都有一個獨立的用戶級頁表。

2、內核態與用戶態

  1. 內核態通常用來執行操作系統的代碼,是一種權限非常高的狀態。
  2. 用戶態是一種用來執行普通用戶代碼的狀態,是一種受監管的普通狀態。

為什么要區分 用戶態 與 內核態 ?

  • 內核空間中存儲的可是操作系統的代碼和數據,權限非常高,絕不允許隨便一個進程對其造成影響
  • 區域的合理劃分也是為了更好的進行管理

2.1 內核如何實現信號的捕捉

  • 用戶態切換到內核態:

    • 需要進行系統調用時。
    • 當前進程的時間片到了,導致進程切換。
    • 產生異常、中斷、陷阱等。
  • 內核態切換到用戶態:

    • 系統調用返回時。
    • 進程切換完畢。
    • 異常、中斷、陷阱等處理完畢。

由用戶態切換為內核態我們稱之為陷入內核。每當我們需要陷入內核的時,本質上是因為我們需要執行操作系統的代碼,比如系統調用函數是由操作系統實現的,我們要進行系統調用就必須先由用戶態切換為內核態。

如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個函數,這稱為捕捉信號。由于信號處理函數的代碼是在用戶空間的,處理過程比較復雜。
舉例如下:

  1. 用戶程序注冊了SIGQUIT信號的處理函數sighandler。
  2. 當前正在執行main函數,這時發生中斷或異常切換到內核態。
  3. 在中斷處理完畢后要返回用戶態的main函數之前檢查到有信號SIGQUIT遞達。
  4. 內核決定返回用戶態后不是恢復main函數的上下文繼續執行,而是執行sighandler函數,sighandler和main函數使用不同的堆棧空間,它們之間不存在調用和被調用的關系,是 兩個獨立的控制流程。
  5. sighandler函數返回后自動執行特殊的系統調用sigreturn再次進入內核態。 如果沒有新的信號要遞達,這次再返回用戶態就是恢復main函數的上下文繼續執行了。
    在這里插入圖片描述

當識別到信號的處理動作是自定義時,能直接在內核態執行用戶空間的代碼嗎?
理論上是可以實現的,但是是絕對不允許的。
很好理解,倘若可以在內核態執行用戶空間的代碼,那么會不會有非法操作?假如在內核態有一個非法操作是將其數據庫都刪掉了,那么這可恢復不了了,因為內核態的權限是足夠大的。雖然在用戶態時沒有足夠的權限做到清空數據庫,但是如果是在內核態時執行了這種非法代碼,那么數據庫就真的被清空了,因為內核態是有足夠權限清空數據庫的。
也就是說,不能讓操作系統直接去執行用戶的代碼,因為操作系統無法保證用戶的代碼是合法代碼,即操作系統不信任任何用戶。

3.捕捉信號

signal函數

signal 函數可以用來 修改信號的執行動作,也叫注冊自定義執行動作。
在這里插入圖片描述
函數理解:

  • 參數 1:
    待操作信號的編號,為 int,單純地傳遞 信號名也是可以的,因為信號名其實就是信號編號的宏定義
  • 參數 2:待注冊的新方法。
    參數2 是一個函數指針,意味著需要傳遞一個 參數為 int,返回值為空的函數對象
    我們需要手動創造一個函數對象,就像下面這樣:
void handler(int signo)
{cout << "當前 " << signo << " 號信號正在嘗試執行相應的動作" << endl;
}

sigaction函數

捕捉信號除了用上面的signal函數之外,我們還可以使用sigaction函數對信號進行捕捉,sigaction函數的函數原型如下:

#include <signal.h>int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);struct sigaction 
{void     (*sa_handler)(int);	//自定義動作void     (*sa_sigaction)(int, siginfo_t *, void *);	//實時信號相關,不用管sigset_t   sa_mask;	//待屏蔽的信號集int        sa_flags;	//一些選項,一般設為 0void     (*sa_restorer)(void);	//實時信號相關,不用管
};

函數說明:

  • 參數1:待操作的信號
  • 參數2:sigaction 結構體,具體成員如上所示
  • 參數3:保存修改前進程的 sigaction 結構體信息
  • 返回值:成功返回 0,失敗返回 -1 并將錯誤碼設置

再了解sigaction結構體中的 sa_mask 字段。
sa_mask:當信號在執行 用戶自定義動作 時,可以將部分信號進行屏蔽,直到 用戶自定義動作 執行完成。
也就是說,我們可以提前設置一批 待阻塞 的 屏蔽信號集,當執行 signum 中的 用戶自定義動作 時,這些 屏蔽信號集 中的 信號 將會被 屏蔽(避免干擾 用戶自定義動作 的執行),直到 用戶自定義動作 執行完成。

使用示范:

#include<iostream>
#include <string.h>
#include <unistd.h>
#include <signal.h>
using namespace std;
struct sigaction act, oldact;
void handler(int signo)
{cout << "get a signo#" << signo << endl;sigaction(2, &oldact, NULL);
}
int main()
{memset(&act, 0, sizeof(act));memset(&oldact, 0, sizeof(oldact));act.sa_handler = handler;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(2, &act, &oldact);while(1){cout << "I am a process..." << endl;sleep(1);}return 0;
}

3.可重入函數

可以被重復進入的函數稱為 可重入函數
在這里插入圖片描述
main函數調用insert函數向一個鏈表head中插入節點node1,插入操作分為兩步,剛做完第一步的 時候,因為硬件中斷使進程切換到內核,再次回用戶態之前檢查到有信號待處理,于是切換 到sighandler函
數,sighandler也調用insert函數向同一個鏈表head中插入節點node2,插入操作的 兩步都做完之后從sighandler返回內核態,再次回到用戶態就從main函數調用的insert函數中繼續 往下執行,先前做第一步之后被打斷,現在繼續做完第二步。結果是,main函數和sighandler先后 向鏈表中插入兩個節點,而最后只有一個節點真正插入鏈表中了。

像上例這樣,insert函數被不同的控制流程調用,有可能在第一次調用還沒返回時就再次進入該函數,這稱為重入,insert函數訪問一個全局鏈表,有可能因為重入而造成錯亂,像這樣的函數稱為 不可重入函數,反之,如果一個函數只訪問自己的局部變量或參數,則稱為可重入(Reentrant) 函數。

如果一個函數符合以下條件之一則是不可重入的

  • 調用了malloc或free,因為malloc也是用全局鏈表來管理堆的。
  • 調用了標準I/O庫函數。標準I/O庫的很多實現都以不可重入的方式使用全局數據結構。

4.volatile關鍵字

volatile 作用:保持內存的可見性,告知編譯器,被該關鍵字修飾的變量,不允許被優化,對該變量的任何操作,都必須在真實的內存中進行操作

我們看到下面代碼:

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;
int flag = 0;
void handler(int signo)
{cout << "get a signal is#" << signo << endl;flag = 1;
}
int main()
{signal(2, handler);cout << "process beginning" << endl;while(!flag){// 什么也不做}cout << "process exit..." << endl;return 0;
}

我們將2號信號進行捕捉,當進程收到2號信號后會將全局變量flag由0置1。也就是說,在進程收到2號信號之前,該進程會一直處于死循環狀態,直到收到2號信號時將flag置1才能夠正常退出。

上面的觀點不一定是正確的!!
當我們修改編譯器的優先級時,將優化級別設為更高是一樣的結果,如果設為 O0 則會符合預期般的運行,說明我們當前的編譯器默認的優化級別是 O0。編譯器就會對上述代碼做出優化!

代碼中的main函數和handler函數是兩個獨立的執行流,而while循環是在main函數當中的,在編譯器編譯時只能檢測到在main函數中對flag變量的使用。此時編譯器檢測到在main函數中并沒有對flag變量做修改操作,在編譯器優化級別較高的時候,就有可能將flag的值設置進寄存器里面。此時main函數在檢測flag時只檢測寄存器里面的值,而handler執行流只是將內存中flag的值置為1了,那么此時就算進程收到2號信號也不會跳出死循環,因為編譯器直接從寄存器上拿到值了。

在這里插入圖片描述

5.SIGCHLD信號

為了避免出現僵尸進程,父進程需要使用wait或waitpid函數等待子進程結束,父進程可以阻塞等待子進程結束,也可以非阻塞地查詢的是否有子進程結束等待清理,即輪詢的方式。采用第一種方式,父進程阻塞就不能處理自己的工作了;采用第二種方式,父進程在處理自己的工作的同時還要記得時不時地輪詢一下,程序實現復雜。

其實,子進程在終止時會給父進程發SIGCHLD信號,該信號的默認處理動作是忽略,父進程可以自 定義SIGCHLD(17)信號的處理函數,這樣父進程只需專心處理自己的工作,不必關心子進程了,子進程 終止時會通知父進程,父進程在信號處理函數中調用wait清理子進程即可

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
void handler(int signo)
{cout << "get a signal#" << signo << endl;int ret = 0;while ((ret = waitpid(-1, NULL, WNOHANG)) > 0){cout << "wait child" << ret << "sucess" << endl;}
}
int main()
{signal(SIGCHLD, handler);pid_t id = fork();if (id == 0){//childcout << "child is running, begin dead#" << getpid() << endl;sleep(3);exit(1);}//fatherwhile (1);return 0;
}

SIGCHLD屬于普通信號,記錄該信號的pending位只有一個,如果在同一時刻有多個子進程同時退出,那么在handler函數當中實際上只清理了一個子進程,因此在使用waitpid函數清理子進程時需要使用while不斷進行清理。

  1. 信號處理期間的附加規則
    在信號處理函數執行期間,內核會自動將該信號加入信號屏蔽字(臨時阻塞)。此時:

    • 若該信號再次觸發,會被標記為未決狀態( s i g p e n d i n g sigpending sigpending位置1),但需等待當前處理函數結束后才會遞送。
    • 對于非實時信號(如SIGINT),多次觸發僅保留一次未決記錄;**實時信號(如SIGRTMIN+1)**則支持排隊,每次觸發均獨立記錄。
  2. 關鍵流程圖釋

    信號觸發 → 檢查是否被阻塞 → 是 → 加入sigpending表(置1)↓ 否  立即遞送處理
    

事實上,由于UNIX的歷史原因,要想不產生僵尸進程還有另外一種辦法:父進程調用signal或sigaction函數將SIGCHLD信號的處理動作設置為SIG_IGN,這樣fork出來的子進程在終止時會自動清理掉,不會產生僵尸進程,也不會通知父進程。系統默認的忽略動作和用戶用signal或sigaction函數自定義的忽略通常是沒有區別的,但這是一個特列。此方法對于Linux可用,但不保證在其他UNIX系統上都可用。

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
using namespace std;
int main()
{signal(SIGCHLD, SIG_IGN);pid_t id = fork();if (id == 0){//childcout << "child is running, child dead:" << getpid() << endl;sleep(3);exit(1);}//fatherwhile (1);return 0;
}

原理:在設置 SIGCHLD 信號的處理動作為忽略后,父進程的 PCB 中有關僵尸進程處理的標記位會被修改,子進程繼承父進程的特性,子進程在退出時,操作系統檢測到此標記位發生了改變,會直接把該子進程進行釋放

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79381.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79381.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79381.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL 數據庫集群部署、性能優化及高可用架構設計

MySQL 數據庫集群部署、性能優化及高可用架構設計 集群部署方案 1. 主從復制架構 傳統主從復制&#xff1a;配置一個主庫(Master)和多個從庫(Slave)GTID復制&#xff1a;基于全局事務標識符的復制&#xff0c;簡化故障轉移半同步復制&#xff1a;確保至少一個從庫接收到數據…

Java 多態:原理與實例深度剖析

一、多態概述 在 Java 面向對象編程體系中&#xff0c;多態是構建靈活、可擴展程序的核心機制之一&#xff0c;與封裝、繼承并稱為面向對象的三大特性。其本質是同一操作作用于不同對象&#xff0c;產生不同的執行結果&#xff0c;這使得程序在運行時能根據實際對象類型動態調…

解決使用寶塔Linux部署前后端分離項目遇到的問題

問題一&#xff1a;訪問域名轉圈圈&#xff0c;顯示404,403 沒有解決跨域問題&#xff0c;在后端yml中設置content&#xff1a;/prod&#xff08;生產環境&#xff09;&#xff0c;在前端.env文件中將http&#xff1a;//127.0.0.1:8080/替換為公網IP&#xff0c;并在vite.conf…

《Python星球日記》 第54天:卷積神經網絡進階

名人說&#xff1a;路漫漫其修遠兮&#xff0c;吾將上下而求索。—— 屈原《離騷》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 目錄 一、深度CNN架構解析1. LeNet-5&#xff08;1998&#xff09;2. AlexNet&#x…

旅游設備生產企業的痛點 質檢系統在旅游設備生產企業的應用

在旅游設備制造行業&#xff0c;產品質量直接關系到用戶體驗與企業口碑。從景區纜車、觀光車到水上娛樂設施&#xff0c;每一件設備的安全性與可靠性都需經過嚴苛檢測。然而&#xff0c;傳統質檢模式常面臨數據分散、流程不透明、合規風險高等痛點&#xff0c;難以滿足旅游設備…

MySql(進階)

一.數據庫約束 約束類型 NOT NULL - 指示某列不能存儲 NULL 值。 (not null不能為NILL) UNIQUE - 保證某列的每行必須有唯一的值。 &#xff08;unique唯一值&#xff09; DEFAULT - 規定沒有給列賦值時的默認值。 &#xff08;default為空給定默認值&#xff09; PRIMARY…

Three.js + React 實戰系列 - 聯系方式提交表單區域 Contact 組件?(表單綁定 + 表單驗證)

對個人主頁設計和實現感興趣的朋友可以訂閱我的專欄哦&#xff01;&#xff01;謝謝大家&#xff01;&#xff01;&#xff01; 在現代網頁中&#xff0c;一個精致的 Contact 區域不僅僅是表單的堆砌&#xff0c;更是用戶與我們建立聯系的第一印象。 在本節課中&#xff0c;我…

UOJ 164【清華集訓2015】V Solution

Description 給定序列 a ( a 1 , a 2 , ? , a n ) a(a_1,a_2,\cdots,a_n) a(a1?,a2?,?,an?)&#xff0c;另有序列 h h h&#xff0c;初始時 h a ha ha. 有 m m m 個操作分五種&#xff1a; add ? ( l , r , v ) \operatorname{add}(l,r,v) add(l,r,v)&#xff1a;…

C++開發過程中的注意事項詳解

目錄 C++開發過程中的注意事項詳解 一、內存管理:避免泄漏與資源浪費 1.1 使用智能指針管理動態內存 1.2 避免手動內存管理的陷阱 1.3 利用RAII機制管理資源 1.4 容器與內存分配 二、安全性:防御攻擊與未定義行為 2.1 輸入驗證與安全編碼 2.2 使用安全的通信協議 2…

Git 時光機:修改Commit信息

前言 列位看官都知道&#xff0c;Git 的每一次 git commit&#xff0c;其中會包含作者&#xff08;Author&#xff09;和提交者&#xff08;Committer&#xff09;的姓名與郵箱。有時可能會因為配置錯誤、切換了開發環境&#xff0c;或者只是單純的手滑&#xff0c;導致 commi…

QSFP+、QSFP28、QSFP-DD接口分別實現40G、100G、200G/400G以太網接口

常用的光模塊結構形式&#xff1a; 1&#xff09;QSFP等效于4個SFP&#xff0c;支持410Gbit/s通道傳輸&#xff0c;可通過4個通道實現40Gbps傳輸速率。與SFP相比&#xff0c;QSFP光模塊的傳輸速率可達SFP光模塊的四倍&#xff0c;在部署40G網絡時可直接使用QSFP光模塊&#xf…

好用的播放器推薦

以下是一些好用的播放器推薦&#xff0c;按照不同平臺和使用場景分類&#xff1a; 電腦端 VLC Media Player 特點&#xff1a;開源、跨平臺&#xff0c;支持幾乎所有的音視頻格式&#xff0c;無需額外安裝解碼器。具備強大的功能&#xff0c;如播放列表管理、視頻和音頻濾鏡、…

Vue基礎(8)_監視屬性、深度監視、監視的簡寫形式

監視屬性(watch)&#xff1a; 1.當被監視的屬性變化時&#xff0c;回調函數(handler)自動調用&#xff0c;進行相關操作。 2.監視的屬性必須存在&#xff0c;才能進行監視&#xff01;&#xff01; 3.監視的兩種寫法&#xff1a; (1).new Vue時傳入watch配置 (2).通過vm.$watc…

AI服務器的作用都有哪些?

根據網絡環境的飛速發展&#xff0c;人工智能技術逐漸入駐到各個行業當中&#xff0c;其中AI服務器則是一種專門用來運行人工智能算法和模型的硬件設備&#xff0c;通常具備高性能計算、大容量存儲和并行計算等多種功能&#xff0c;本文就來詳細講解一下AI服務器的作用&#xf…

[250508] Linux 內核瘦身:棄用 i486 及早期 586 CPU 支持

目錄 Linux 內核計劃精簡&#xff1a;將移除對古董級 CPU 的支持 Linux 內核計劃精簡&#xff1a;將移除對古董級 CPU 的支持 核心動態&#xff1a; Linux 內核開發社區正計劃一項重要的代碼清理工作&#xff0c;目標是移除對非常古老的 i486 及早期 586 (如早期奔騰) CPU 架構…

ROM詳解

一、ROM基礎原理 定義與特性 ROM&#xff08;Read-Only Memory&#xff0c;只讀存儲器&#xff09;是一種非易失性存儲器&#xff0c;數據在制造或編程后永久保存&#xff0c;斷電后不丟失。其核心特性為數據不可修改&#xff08;或需特殊條件修改&#xff09;。 存儲原理&…

解決虛擬機掛起之后的網絡問題

相信很多人都有遇到過自己在VM上面手滑點了個掛起然后就連不了網絡的情況吧&#xff0c;我也遇到了&#xff0c;下面是我的解決辦法&#xff0c;希望對大家有所幫助&#xff01; 我運行完如下&#xff1a; 基本上出現綠色的就說明網絡連上啦&#xff01;

在Star-CCM+中實現UDF并引用場數據和網格數據

在Star-CCM中實現UDF并引用場數據和網格數據 Star-CCM中的用戶自定義函數(UDF)允許用戶通過Java或C/C編程擴展軟件功能。下面我將詳細介紹如何實現UDF并引用模擬數據。 1. UDF基礎實現方法 1.1 創建UDF的步驟 在Star-CCM中&#xff0c;右鍵點擊"工具" → “用戶函…

ConnectionResetError(10054, ‘遠程主機強迫關閉了一個現有的連接,Python爬蟲

文章目錄 ConnectionResetError(10054, 遠程主機強迫關閉了一個現有的連接1.問題描述2.嘗試的解決方法&#xff08;均未生效&#xff09;2.1 請求重試機制2.2 模擬瀏覽器請求頭2.3 關閉連接資源2.4 延遲訪問 3.解決方案&#xff1a;使用 proxy_pool IP 代理池最后參考文章 Conn…

Redis相關命令詳解與原理(一)

目錄 Redis是什么&#xff1f; Redis 的特點和功能 Redis工作模式 與MySQL的區別 安裝編譯和啟動 redis的value類型編碼 string類型 基礎命令 應用 1.對象存儲 2.累加器 3.分布式鎖 4.位運算 list類型 基礎命令 應用 1.棧&#xff08;先進后出 FILO&#xff0…