Linux 進程信號學習筆記:從概念到實操

一、Linux 信號基本概念

1.1 生活角度理解信號

我們可以把進程比作等待快遞的人,信號就像快遞:

  • 識別信號:就像我們知道快遞來了該?怎么處理,進程對信號的識別是內核程序員預先編寫的內置特性,即使信號沒產生,進程也知道該如何處理。
  • 信號延遲處理:比如正在打游戲時收到快遞通知,會等游戲結束再去取,進程收到信號后,若在執行優先級更高的任務,會在合適的時候處理信號。
  • 信號記錄:從收到快遞通知到取到快遞的這段時間,我們會記住有快遞要取,進程收到信號后,在未處理前也會暫時記錄信號。
  • 信號處理方式:處理快遞有打開使用(默認動作)、送給他人(自定義動作)、扔在一邊(忽略)三種方式,進程處理信號也有默認、自定義、忽略三種方式,自定義處理信號也叫信號捕捉。

1.2 技術角度理解信號

信號是進程之間事件異步通知的一種方式,屬于軟中斷。比如在 Shell 下啟動一個前臺進程,當我們按下Ctrl+C,會產生一個硬件中斷,被操作系統獲取后解釋成SIGINT(2 號信號)發送給前臺進程,前臺進程收到信號后會退出,這就是信號的實際應用。

1.3 查看信號

在 Linux 系統中,我們可以通過相關命令查看信號,每個信號都有對應的編號和宏定義名稱,這些宏定義可在signal.h中找到。例如:

  • SIGINT(2 號信號):來自鍵盤的中斷信號。
  • SIGQUIT(3 號信號):來自鍵盤的退出信號,會生成 core dump 文件。
  • SIGKILL(9 號信號):殺死進程的信號,無法被捕捉和忽略。

我們也可以通過man 7 signal命令查看每個信號的產生條件和默認處理動作,部分常見信號如下表:

SignalStandardActionComment
SIGABRTP1990Core來自 abort (3) 的中止信號
SIGALRMP1990Term來自 alarm (2) 的定時器信號
SIGBUSP2001Core總線錯誤(不良內存訪問)
SIGCHLDP1990Ign子進程停止或終止
SIGINTP1990Term來自鍵盤的中斷

二、信號產生的一般方式

2.1 通過終端按鍵產生信號

  • Ctrl+C(SIGINT,2 號信號):發送中斷信號,默認終止前臺進程。
    • 示例:編寫一個簡單的循環程序,運行后按下Ctrl+C,進程會退出。
#include <iostream>
#include <unistd.h>
int main() {while (true) {std::cout << "I am a process, I am waiting signal!" << std::endl;sleep(1);}return 0;
}

編譯運行:g++ sig.cc -o sig && ./sig,按下Ctrl+C,進程終止

  • Ctrl+\(SIGQUIT,3 號信號):發送退出信號,默認終止進程并生成 core dump 文件,用于事后調試。
    • 示例:修改上述程序,捕捉SIGQUIT信號。
#include <iostream>
#include <unistd.h>
#include <signal.h>
void handler(int signumber) {std::cout << "我是: " << getpid() << ", 我獲得了一個信號: " << signumber << std::endl;
}
int main() {std::cout << "我是進程: " << getpid() << std::endl;signal(SIGQUIT/*3*/, handler);while (true) {std::cout << "I am a process, I am waiting signal!" << std::endl;sleep(1);}return 0;
}

編譯運行后,按下Ctrl+\,會輸出信號編號,若注釋掉信號捕捉代碼,按下Ctrl+\,進程會退出并生成 core dump 文件。

  • Ctrl+Z(SIGTSTP,20 號信號):發送停止信號,默認將當前前臺進程掛起到后臺。
    • 示例:運行上述未捕捉SIGTSTP信號的循環程序,按下Ctrl+Z,進程會被掛起,使用jobs命令可查看后臺進程,使用fg命令可將后臺進程調回前臺。

2.1.2? 實操:使用signal函數自定義SIGINT信號的處理方式

以下是一個小實驗,大家可以練下手加深理解

signal?函數用于設置信號的處理方式,它的原型是:

#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int);
  • signum:要設置處理方式的信號編號,比如?SIGINT
  • handler:指向信號處理函數的指針。信號處理函數的原型是?void handler(int signum),其中?signum?是接收到的信號編號。

代碼解釋

  • 首先,我們包含了必要的頭文件:stdio.h(用于輸入輸出)、signal.h(用于信號相關操作)、unistd.h(用于?sleep?函數)。

  • 定義了自定義的信號處理函數?sigcb,它接收一個?int?類型的參數?signum(即接收到的信號編號),在函數內部打印出接收到的信號值。

  • 在?main?函數中,使用?signal(SIGINT, sigcb)?來設置?SIGINT?信號的處理函數為?sigcb。這樣,當進程接收到?SIGINT?信號時,就會調用?sigcb?函數而不是默認的終止進程操作。

  • 然后打印提示信息,接著通過一個無限循環?while (1)?讓程序保持運行,sleep(1)?是為了避免程序過度占用 CPU。

編譯與運行

  1. 編譯代碼:使用?gcc?編譯器,在終端中輸入命令?gcc -o sig_demo sig_demo.c(假設代碼文件名為?sig_demo.c)。

  2. 運行程序:在終端中輸入?./sig_demo,程序會開始運行并打印提示信息。

  3. 測試信號:按下?Ctrl + C,此時會觸發?SIGINT?信號,程序會調用?sigcb?函數,打印出類似?接收到信號,信號值為:2SIGINT?的值通常為 2)的信息,而不是終止程序。

執行結果截圖說明

  • 編譯運行后,終端會顯示 “程序正在運行,按下ctrl+c發送SIGINT信號”。

  • 當按下?Ctrl + C?時,終端會打印 “接收到信號為:2”,然后程序繼續運行(因為我們的處理函數沒有終止進程,而是讓程序繼續在循環中運行)。如果多次按下?Ctrl + C,會多次打印該信息。

SIGINT(Ctrl+C)被我們自定義處理了,但系統還有其他信號可以終止進程,比如?SIGQUIT(通常由?Ctrl+\?觸發)。

通過這個例子,你可以清楚地看到如何使用?signal?函數來自定義信號的處理方式,以及?SIGINT?信號的觸發和處理過程。

2.1.3? 實操2:使用sigaction函數自定義SIGINT信號的處理方式

sigaction?函數是比?signal?函數更強大、更可移植的信號處理接口。它可以更精細地控制信號的處理行為。sigaction?函數的原型如下:

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • signum:要設置處理方式的信號編號,比如?SIGINT
  • act:指向?struct sigaction?結構體的指針,該結構體包含了新的信號處理方式等信息。
  • oldact:指向?struct sigaction?結構體的指針,用于保存原來的信號處理方式(可以為?NULL,表示不保存)。

struct sigaction?結構體的定義大致如下:

struct sigaction {void (*sa_handler)(int);sigset_t sa_mask;int sa_flags;void (*sa_sigaction)(int, siginfo_t *, void *);
};
  • sa_handler:指向信號處理函數的指針,和?signal?函數中的處理函數類似,處理函數原型為?void handler(int signum)
  • sa_mask:指定在信號處理函數執行期間,需要阻塞的信號集合。
  • sa_flags:用于設置信號處理的一些標志,比如?SA_SIGINFO?等。
  • sa_sigaction:當?sa_flags?中設置了?SA_SIGINFO?標志時,使用該函數指針所指向的函數來處理信號,這個函數可以獲取更多關于信號的信息,原型為?void handler(int signum, siginfo_t *info, void *context)

代碼實現

我們編寫一個 C 程序,使用?sigaction?函數來自定義?SIGINT?信號的處理方式:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 自定義的信號處理函數
void sigcb(int signum) {printf("接收到信號,信號值為:%d\n", signum);
}int main() {struct sigaction act;// 設置信號處理函數為 sigcbact.sa_handler = sigcb;// 清空 sa_mask,即處理信號期間不阻塞其他信號sigemptyset(&act.sa_mask);// 設置 sa_flags 為 0,使用默認的標志act.sa_flags = 0;// 使用 sigaction 函數設置 SIGINT 信號的處理方式sigaction(SIGINT, &act, NULL);printf("程序正在運行,按下 Ctrl + C 發送 SIGINT 信號\n");// 讓程序保持運行,以便我們可以發送信號while (1) {sleep(1);}return 0;
}

代碼解釋

  • 首先包含必要的頭文件:stdio.h(輸入輸出)、signal.h(信號相關操作)、unistd.hsleep?函數)。

  • 定義自定義的信號處理函數?sigcb,功能是打印接收到的信號值。

  • 在?main?函數中,定義?struct sigaction?類型的變量?act

  • 設置?act?的?sa_handler?成員為我們自定義的處理函數?sigcb

  • 使用?sigemptyset?函數清空?sa_mask?成員,這樣在處理?SIGINT?信號期間,不會阻塞其他信號。

  • 將?sa_flags?成員設置為?0,使用默認的標志。

  • 調用?sigaction?函數,將?SIGINT?信號的處理方式設置為?act?所指定的方式,第三個參數為?NULL,表示不保存原來的信號處理方式。

  • 打印提示信息后,通過無限循環讓程序保持運行,sleep(1)?避免程序過度占用 CPU。

編譯與運行

  1. 編譯代碼:使用?gcc?編譯器,在終端中輸入命令?gcc -o sigaction_demo sigaction_demo.c(假設代碼文件名為?sigaction_demo.c)。

  2. 運行程序:在終端中輸入?./sigaction_demo,程序開始運行并打印提示信息。

  3. 測試信號:按下?Ctrl + C,觸發?SIGINT?信號,程序會調用?sigcb?函數,打印出類似?接收到信號,信號值為:2SIGINT?的值通常為 2)的信息,而不是終止程序。

執行結果截圖說明

  • 編譯運行后,終端會顯示 “程序正在運行,按下 Ctrl + C 發送 SIGINT 信號”。

  • 當按下?Ctrl + C?時,終端會打印 “接收到信號,信號值為:2”,然后程序繼續運行(因為我們的處理函數沒有終止進程,程序在循環中繼續運行)。多次按下?Ctrl + C,會多次打印該信息。

通過這個例子,你可以掌握?sigaction?函數的使用方法,以及如何更精細地控制信號的處理方式。

2.2 調用系統命令向進程發信號

我們可以使用kill命令向指定進程發送信號,例如:

  1. 后臺運行一個死循環程序:./sig &sig為上述編譯生成的可執行文件)。
  2. 查看進程 ID:ps ajx | grep sig,獲取進程的 PID。
  3. 向進程發送SIGSEGV(11 號信號,段錯誤信號):kill -SIGSEGV PID(或kill -11 PID),進程會因段錯誤終止。

2.3 使用函數產生信號

2.3.1 kill 函數

kill函數可以給一個指定的進程發送指定的信號,函數原型如下:

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
  • 參數說明
    • pid:目標進程的 PID。
    • sig:要發送的信號編號。
  • 返回值:成功返回 0,失敗返回 - 1,并設置errno
  • 示例:實現自己的 kill 命令
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
// mykill -signumber pid
int main(int argc, char *argv[]) {if (argc != 3) {std::cerr << "Usage: " << argv[0] << " -signumber pid" << std::endl;return 1;}int number = std::stoi(argv[1] + 1); // 去掉“-”pid_t pid = std::stoi(argv[2]);int n = kill(pid, number);return n;
}

編譯生成mykill后,可像kill命令一樣使用,例如./mykill -2 PID,向指定 PID 的進程發送 2 號信號。

2.3.2 raise 函數

raise函數可以給當前進程發送指定的信號(自己給自己發信號),函數原型如下:

#include <signal.h>
int raise(int sig);
  • 參數說明sig:要發送的信號編號。
  • 返回值:成功返回 0,失敗返回非 0。
  • 示例
    #include <iostream>
    #include <unistd.h>
    #include <signal.h>
    void handler(int signumber) {// 整個代碼就只有這一處打印std::cout << "獲取了一個信號: " << signumber << std::endl;
    }
    int main() {signal(2, handler); // 先對2號信號進行捕捉// 每隔1S,自己給自己發送2號信號while (true) {sleep(1);raise(2);}return 0;
    }

編譯運行后,每隔 1 秒會輸出 “獲取了一個信號: 2”。

2.3.3 abort 函數

abort函數使當前進程接收到信號而異常終止,函數原型如下:

#include <stdlib.h>
void abort(void);
  • 說明abort函數總是會成功,沒有返回值,它會給當前進程發送SIGABRT(6 號信號)。
  • 示例
    #include <iostream>
    #include <unistd.h>
    #include <stdlib.h>
    #include <signal.h>
    void handler(int signumber) {// 整個代碼就只有這一處打印std::cout << "獲取了一個信號: " << signumber << std::endl;
    }
    int main() {signal(SIGABRT, handler);while (true) {sleep(1);abort();}return 0;
    }

編譯運行后,會輸出 “獲取了一個信號: 6”,然后進程異常終止,即使捕捉了SIGABRT信號,進程也會退出。

2.4 由軟件條件產生信號

alarm函數和SIGALRM(14 號信號)為例,alarm函數可以設定一個鬧鐘,告訴內核在指定秒數后給當前進程發SIGALRM信號,該信號的默認處理動作是終止當前進程,函數原型如下:

  • 參數說明seconds:鬧鐘時間,單位為秒。若seconds為 0,表示取消以前設定的鬧鐘。
  • 返回值:返回 0 或者以前設定的鬧鐘時間還余下的秒數。
2.4.1 基本 alarm 驗證 - 體會 IO 效率問題
  • IO 多的情況
#include <iostream>
#include <unistd.h>
#include <signal.h>
int main() {int count = 0;alarm(1);while (true) {std::cout << "count : " << count << std::endl;count++;}return 0;
}

編譯運行后,1 秒內輸出的計數較少,因為std::cout是 IO 操作,效率較低。

  • IO 少的情況
#include <iostream>
#include <unistd.h>
#include <signal.h>
int count = 0;
void handler(int signumber) {std::cout << "count : " << count << std::endl;exit(0);
}
int main() {signal(SIGALRM, handler);alarm(1);while (true) {count++;}return 0;
}

編譯運行后,1 秒內輸出的計數會非常大,因為僅進行變量自增操作,IO 操作少,效率高。

2.4.2 設置重復鬧鐘
#include <iostream>
#include <unistd.h>
#include <signal.h>
int gcount = 0;
void handler(int signo) {std::cout << "gcount : " << gcount << std::endl;gcount++;int n = alarm(1); // 重設鬧鐘,會返回上一次鬧鐘的剩余時間std::cout << "剩余時間 : " << n << std::endl;
}
int main() {std::cout << "我的進程pid是: " << getpid() << std::endl;alarm(1); // 一次性的鬧鐘,超時alarm會自動被取消signal(SIGALRM, handler);while (true) {pause(); // 等待信號std::cout << "我醒來了..." << std::endl;}return 0;
}

編譯運行后,每隔 1 秒會輸出計數和剩余時間,實現了重復鬧鐘的功能。pause函數會使調用進程(或線程)睡眠,直到收到一個終止進程的信號或一個導致調用信號捕捉函數的信號。

2.5 硬件異常產生信號

硬件異常被硬件檢測到并通知內核,然后內核向當前進程發送適當的信號。例如:

  • 除零異常:當進程執行除以 0 的指令時,CPU 的運算單元會產生異常,內核將這個異常解釋為SIGFPE(8 號信號)發送給進程。
  • 示例
    #include <stdio.h>
    #include <signal.h>
    void handler(int sig) {printf("catch a sig : %d\n", sig);
    }
    int main() {signal(SIGFPE, handler); // 8) SIGFPEsleep(1);int a = 10;a /= 0;while (1);return 0;
    }

編譯運行后,會不斷輸出 “catch a sig : 8”,因為除零異常一直存在,內核會持續發送SIGFPE信號。

  • 非法內存訪問:當進程訪問了非法內存地址,MMU(內存管理單元)會產生異常,內核將這個異常解釋為SIGSEGV(11 號信號)發送給進程。
    • 示例
#include <stdio.h>
#include <signal.h>
void handler(int sig) {printf("catch a sig : %d\n", sig);
}
int main() {signal(SIGSEGV, handler);sleep(1);int *p = NULL;*p = 100;while (1);return 0;
}

編譯運行后,會不斷輸出 “catch a sig : 11”,因為非法內存訪問的異常一直存在。

三、信號遞達和阻塞的概念與原理

3.1 相關概念

  • 信號遞達(Delivery):實際執行信號的處理動作。?
  • 信號未決(Pending):信號從產生到遞達之間的狀態。
  • 信號阻塞(Block):進程可以選擇阻塞某個信號,被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。

注意:阻塞和忽略是不同的,只要信號被阻塞就不會遞達,而忽略是在遞達之后可選的一種處理動作。

3.2 在內核中的表示

在進程控制塊(task_struct)中,有三個與信號相關的重要部分:

  • block:信號屏蔽字,用sigset_t類型表示,每個 bit 代表對應信號是否被阻塞。
  • pending:未決信號集,同樣用sigset_t類型表示,每個 bit 代表對應信號是否處于未決狀態。
  • handler:信號處理動作數組,每個元素是一個函數指針,指向該信號的處理函數,若為SIG_DFL表示默認處理動作,SIG_IGN表示忽略該信號。

例如,對于SIGINT(2 號信號),若block中對應的 bit 為 1,表示該信號被阻塞;若pending中對應的 bit 為 1,表示該信號處于未決狀態;handler中對應的函數指針指向該信號的處理函數。

3.3 信號集操作函數

sigset_t類型用于表示信號集,我們不能直接操作sigset_t變量的內部數據,需要使用專門的函數:

3.3.1 初始化和修改信號集
  • sigemptyset:初始化信號集,使其中所有信號的對應 bit 清零,表示該信號集不包含任何有效信號。

#include <signal.h>
int sigemptyset(sigset_t *set);

sigfillset:初始化信號集,使其中所有信號的對應 bit 置位,表示該信號集包含系統支持的所有信號。

#include <signal.h>
int sigfillset(sigset_t *set);

sigaddset:在信號集中添加某種有效信號。

#include <signal.h>
int sigaddset(sigset_t *set, int signo);

sigdelset:在信號集中刪除某種有效信號。

#include <signal.h>
int sigdelset(sigset_t *set, int signo);
  • 返回值:以上四個函數成功返回 0,出錯返回 - 1。
3.3.2 判斷信號是否在信號集中

sigismember:判斷一個信號集的有效信號中是否包含某種信號,若包含則返回 1,不包含則返回 0,出錯返回 - 1。

#include <signal.h>
int sigismember(const sigset_t *set, int signo);
3.3.3 讀取或更改進程的信號屏蔽字

sigprocmask:讀取或更改進程的信號屏蔽字(阻塞信號集)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
  • 參數說明
    • how:指示如何更改信號屏蔽字,取值如下:
      • SIG_BLOCKset包含了我們希望添加到當前信號屏蔽字的信號,相當于mask = mask | set
      • SIG_UNBLOCKset包含了我們希望從當前信號屏蔽字中解除阻塞的信號,相當于mask = mask & ~set
      • SIG_SETMASK:設置當前信號屏蔽字為set所指向的值,相當于mask = set
    • set:若非空指針,則根據how更改進程的信號屏蔽字;若為空指針,則不更改信號屏蔽字。
    • oset:若非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出;若為空指針,則不讀取信號

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

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

相關文章

解決多種類潮濕敏感元器件的多溫度、多時長的排潮烘干

鎧德科技ESD烘箱針對復雜電路產品的排潮烘干需求&#xff0c;可通過以下技術路徑實現多品類元器件的高效兼容處理&#xff1a;多溫區獨立控制系統采用蜂窩式加熱模塊陣列&#xff0c;每個0.6m獨立溫區可設置1℃精度支持同時運行3種不同溫度曲線&#xff08;典型值&#xff1a;8…

obdumper和obloader遷移OceanBase業務庫(一):實施手冊

obdumper和obloader遷移OceanBase業務庫&#xff08;一&#xff09;&#xff1a;實施手冊導出前準備全庫&#xff08;模式&#xff09;數據導出全庫&#xff08;模式&#xff09;數據導入導入后檢查環境信息&#xff1a;OceanBase v4.3.5單機部署&#xff0c;MySQL租戶OBDUMPER…

SQLSugar 快速入門:從基礎到實戰查詢與使用指南

目錄 ?編輯 一、SQLSugar 簡介 二、SQLSugar 環境搭建 2.1 安裝 SQLSugar 2.1.1 通過 Visual Studio NuGet 圖形化界面安裝 2.1.2 通過 NuGet 命令行安裝 2.2 引用 SQLSugar 命名空間 三、SQLSugar 核心初始化配置 3.1 基礎初始化&#xff08;非 IOC 模式&#xff09…

Python與Rust語法對比詳解:從入門到精通

Python與Rust語法對比詳解&#xff1a;從入門到精通 前言 Python和Rust作為當今最受關注的編程語言&#xff0c;分別代表了動態類型和靜態類型語言的典型特征。本文將從語法層面深入對比這兩種語言&#xff0c;幫助開發者理解它們的設計理念和使用場景。1. 基礎語法結構 1.1 He…

視頻加水印_帶gif 加動態水印 gif水印 視頻浮動水印

如果你有一個視頻&#xff0c;你想給它加一個水印&#xff0c;讓水印浮動&#xff0c;而且加的還是 GIF 動態圖片水印&#xff0c;那么你可以使用這個工具。首先把你的兩個文件拖進來&#xff0c;然后點擊第三個按鈕。加好了&#xff0c;打開看一下&#xff0c;我們看到這個水印…

C# 字符和字符串

原文&#xff1a;C# 字符和字符串_w3cschool 請勿將文章標記為付費&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; C&#xff03;字符和字符串 C&#xff03;的 char 類型別名 System.Char 類型表示 Unicode 字符。 在單引號中指定char字面值&#xff1a; …

IntelliJ IDEA 反編譯JAR包記錄

本文記錄了使用 IntelliJ IDEA 內置反編譯工具對 JAR 包進行反編譯的詳細步驟&#xff0c;方便日后快速參考和使用。 &#x1f6e0;? 工具準備 反編譯工具使用的是 IntelliJ IDEA 內置的 Java 反編譯器&#xff0c;無需額外安裝其他工具。 工具路徑&#xff1a; /Applications…

KingbaseES JDBC 驅動詳解:連接、配置與最佳實踐

目錄KingbaseES JDBC 驅動詳解&#xff1a;連接、配置與最佳實踐引言一、JDBC 基礎與 KingbaseES 實現1.1 JDBC 技術概述1.2 KingbaseES JDBC 驅動特點二、環境配置與驅動獲取2.1 驅動包選擇與依賴管理2.2 國密算法支持2.3 驅動版本信息獲取三、數據庫連接管理3.1 使用 DriverM…

破解 Aspose.Words 24.12,跳過 License 校驗,實現 HTML 向 Word/PDF 的轉換,附帶 Demo。

說明 在Java生態中處理Office文檔時&#xff0c;開發人員常面臨格式兼容性和功能完整性的挑戰。商業組件Aspose以其卓越的文檔處理能力成為企業級解決方案之一&#xff0c;支持Word、Excel、PDF等多種格式的精準轉換與操作。 請勿用于商業用途&#xff0c;若侵權請聯系我。 參考…

php連接rabbitmq例子

首先確保安裝好了Rabbitmq服務器。1.新建一個空白php項目&#xff0c;安裝php客戶端庫&#xff1a;composer require php-amqplib/php-amqplib2.生產者然后添加生產者代碼 (producer.php)<?php require_once __DIR__ . /vendor/autoload.php;use PhpAmqpLib\Connection\AMQ…

Docker Swarm vs Kubernetes vs Nomad:容器編排方案對比與選型建議

Docker Swarm vs Kubernetes vs Nomad&#xff1a;容器編排方案對比與選型建議 在微服務和云原生時代&#xff0c;容器編排成為支持大規模容器化應用的關鍵技術。本文將從問題背景、方案對比、優缺點分析、選型建議以及實際應用效果驗證五個方面&#xff0c;對Docker Swarm、Ku…

似然函數對數似然函數負對數似然函數

目錄1. 似然函數的定義2. 對數似然函數的定義3. 負對數似然函數的定義4. 負對數似然函數的優化5. 具體應用示例5.1 邏輯回歸中的負對數似然函數5.2 優化邏輯回歸的負對數似然函數1. 似然函數的定義 似然函數L(θ∣X)L(\theta | X)L(θ∣X)是在給定參數θ\thetaθ 下&#xff0…

鴻蒙地址選擇庫(ArkTs UI)

功能點&#xff1a;支持三級聯動、點擊確認返回省市區code及name&#xff08;安心&#xff09;、布局可以高度自定義 實現&#xff1a;TextPicker讀取本地json&#xff08;也可用第三方的json 不過需要自行調整了&#xff09; 先上圖吧、廢話下面再說&#xff1a; 湊和看吧、…

YOLO 目標檢測:數據集構建(LabelImg 實操)、評估指標(mAP/IOU)、 NMS 后處理

文章目錄基本知識介紹1.視覺處理三大任務2.訓練、驗證、測試、推理3.數據集3.1 數據集格式3.2 數據集標注4.上游任務和下游任務YOLO指標1.真實框&#xff08;Ground Truth Box&#xff09;與邊界框&#xff08;Bounding Box&#xff09;2.交并比&#xff08;IOU&#xff09;3.置…

進程狀態 —— Linux內核(Kernel)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄進…

計算機視覺與深度學習 | 低照度圖像處理算法綜述:發展、技術與趨勢

文章目錄 一、發展歷程:從傳統模型到智能融合 (一)傳統模型構建階段(1970s-2016) (二)深度學習應用階段(2017-2020) (三)硬件-算法協同階段(2021至今) 二、技術分類與性能對比 (一)傳統方法體系 (二)深度學習方法 1. 監督學習模型 2. 無監督/自監督方法 3. 混…

責任鏈模式實踐-開放銀行數據保護及合規

責任鏈模式介紹什么是責任鏈模責任鏈模式是一種行為設計模式&#xff0c; 允許你將請求沿著處理者鏈進行發送。 收到請求后&#xff0c; 每個處理者均可對請求進行處理&#xff0c; 或將其傳遞給鏈上的下個處理者。責任鏈模式結構偽代碼基于責任鏈的開放銀行數據保護及合規實踐…

npm install --global @dcloudio/uni-cli 時安裝失敗

這個日志顯示在執行 npm install --global dcloudio/uni-cli 時安裝失敗&#xff0c;核心錯誤是 UNABLE_TO_GET_GET_ISSUER_CERT_LOCALLY&#xff08;無法獲取本地頒發者證書&#xff09;&#xff0c;屬于 HTTPS 證書驗證失敗 問題。錯誤原因npm 訪問官方 registry&#xff08;…

吱吱企業通訊軟件可私有化部署,構建安全可控的通訊辦公平臺

在當今激烈的市場競爭環境中&#xff0c;企業通訊已成為制勝的關鍵因素。吱吱作為一款專為企業管理設計的IM即時辦公通訊軟件&#xff0c;提供了高度安全的通訊辦公環境&#xff0c;確保信息在內部流通的安全性與高效性&#xff0c;為企業數字化轉型奠定了堅實的基礎。 一、私有…

暄桐:唯有認真思考過死亡,才足以應對日常

暄桐是一間傳統美學教育教室&#xff0c;創辦于2011年&#xff0c;林曦是創辦人和授課老師&#xff0c;教授以書法為主的傳統文化和技藝&#xff0c;皆在以書法為起點&#xff0c;親近中國傳統之美&#xff0c;以實踐和所得&#xff0c;滋養當下生活。初聽莊子在妻子離世后“鼓…