【Linux】進程控制:創建、終止、等待與替換全解析

文章目錄

  • 前言
  • 一、重談進程創建
  • 二、進程終止
    • 2.1 正常終止的退出碼機制
    • 2.2 異常終止的信號機制
    • 2.3 進程常見的退出方法
  • 三、進程等待:避免僵尸進程的關鍵
    • 3.1 進程等待的必要性
    • 3.2 進程等待的兩個系統調用接口
      • 3.2.1 wait()
      • 3.2.2 waitpid()
      • 區別
  • 四、進程程序替換
    • 4.1 進程替換原理(單進程)
    • 4.2 多進程版程序替換效果——驗證程序替換接口
    • 4.3 進程替換的接口
  • 總結


前言

本文將用最直白的語言帶你掌握Linux進程管理的四大核心操作!包含大量代碼示例與圖解,建議邊看邊動手實踐!


一、重談進程創建

當我們使用fork()系統調用創建子進程時,父子進程的執行順序并非固定,而是由操作系統的進程調度器決定。這種不確定性源于現代操作系統的并發特性

可能輸出結果:
父進程PID: 1234
子進程PID: 1235或
子進程PID: 1235
父進程PID: 1234

1.2 調度機制解析

調度策略說明典型系統
完全公平調度(CFS)基于虛擬運行時間分配CPU時間片Linux默認
實時調度優先級驅動嵌入式系統
輪轉調度均分時間片早期Unix系統

二、進程終止

2.1 正常終止的退出碼機制

為什么main函數總是return 0 返回,這個0去哪里了?為什么

進程退出場景:

  • 代碼運行完畢,結果正確
  • 代碼運行完畢,結果不正確
  • 代碼異常終止

在程序運行期間,我們通常并不關心意料之中的【程序正常運行且結果正確】的情況,反而那些結果有誤、異常退出的情況能夠讓程序員及時發現問題原因并解決它。
程序中的return 0表示的是進程的退出碼,表示進程的運行結果是否正確

此外,在系統層面上,進程運行時,一般來說是父進程最關心自己的子進程的運行狀態,所以退出碼是直接向父進程呈現的。
換言之,在子進程正常運行且退出時(返回0),父進程并不關心,更多的是關心子進程運行失敗的原因并轉交給用戶,此時,程序就可以用return返回不同的值,來表示不同的出錯原因。

我們可以使用以下指令來查看最近一次運行的進程返回的退出碼是多少:

$ echo $? # $?表示最近一個程序運行的退出碼

此外,在C語言中有將退出碼轉化為錯誤信息的strerror()函數

//打印所有退出碼表示的信息
#include <string.h>int main()
{int i = 0;for(; i<200; i++){printf("%d: %s\n",i,strerror(i));}return 0;
}

在這里插入圖片描述
此外,在我們平常使用的cd指令、pwd指令等,底層實現也是一段程序,同樣會返回錯誤碼信息:

舉例: ls 不存在的目錄時,返回2錯誤碼
(No such file or directory)

在這里插入圖片描述

2.2 異常終止的信號機制

在進程運行時,正常的順序是先檢查是否異常,再判斷結果信息,只要是程序異常終止了,退出碼就沒有任何意義了。例如野指針問題或者除0錯誤等都會觸發硬件級的異常問題,操作系統會直接給進程返回某種信號結束進程(kill)。
【這部分的內容我們會在后面的信號章節詳細為大家講解】

信號說明觸發場景
SIGSEGV11段錯誤非法內存訪問
SIGFPE8算術異常除零操作
SIGKILL9強制終止kill -9

2.3 進程常見的退出方法

  1. return 0(在 main 函數中)
    在 main 函數中使用 return 0 表示程序正常終止,返回值 0 作為進程的退出狀態碼。

觸發 main 函數的隱式 exit 調用,
執行標準庫的清理工作(如刷新 I/O 緩沖區、關閉文件流)。
最終通過系統調用(如 _exit)終止進程。

int main() {printf("Hello"); // 無換行符,但 return 會刷新緩沖區return 0;        // 輸出 Hello
}
  1. exit(int status)
    標準庫函數(stdlib.h),立即終止進程,返回狀態碼 status

刷新所有標準 I/O 緩沖區(如 printf 未輸出的內容)。
關閉所有打開的流(FILE 類型)。
最終調用 _exit 終止進程。

#include <stdlib.h>
void func() {printf("World");  // 無換行符exit(0);          // 輸出 World
}
  1. _exit(int status)
    系統調用(unistd.h),直接終止進程,返回狀態碼 status

不執行任何清理:
不刷新 I/O 緩沖區(可能導致數據丟失)。
不調用 atexit 注冊的函數。
立即終止進程。

#include <unistd.h>
int main() {printf("Hello");  // 無換行符_exit(0);         // 無輸出(緩沖區未刷新)
}

在這里插入圖片描述

方式所屬庫/系統調用清理操作(I/O 緩沖區、atexit 函數)適用場景
return 0C 標準庫是(隱式調用 exit)main 函數正常退出
exit()C 標準庫任意位置終止并清理資源
_exit()系統調用快速終止,避免干擾(如子進程)

三、進程等待:避免僵尸進程的關鍵

通過系統調用wait / waitpid,來對子進程進行狀態檢測與回收的功能。

3.1 進程等待的必要性

  1. 避免僵尸進程(Zombie Process)
    子進程退出后,若父進程未調用等待函數,子進程的退出狀態會殘留在內核中,成為僵尸進程(占用 PID,但無法被調度,并且)。
    后果:大量僵尸進程會導致 PID 耗盡,系統無法創建新進程。

  2. 同步父子進程
    父進程可能需要等待子進程完成特定任務后再繼續執行(如數據處理、文件讀寫)。

  3. 獲取子進程退出狀態
    父進程需知道子進程是正常退出(如返回碼)、被信號終止,還是其他異常情況。【這里可以通過系統調用來獲取不同的值來表示不同的情況,在wait和waitpid接口中存在參數status(輸出型參數,由操作系統填充,如果傳遞NULL,表示不關心子進程的退出狀態信息。),status在系統中以整形的方式存在,但不同區間的比特位代表不同的信息(如下圖)】

pid_t wait(int *status);
pid_ t waitpid(pid_t pid, int *status, int options);

進程之間具有獨立性,因此父進程獲取子進程運行狀態不能簡單地通過訪問某個全局變量獲取子進程狀態因為父進程無法看到該變量(每個進程有自己的獨立的進程地址空間),只能通過操作系統調用接口來實現。

關于status參數,它是一個整型指針,用來存儲子進程的退出狀態。status不能簡單的當作整形來看待,可以當作位圖來看待,具體細節如下圖(只研究status低16比特位),表示含義為:
如果進程正常退出,那么高八位為進程的退出狀態碼;如果進程被信號所殺(異常中止),那么低七位表示信號碼,第八位表示core dump標志核心轉儲,是操作系統在程序異常終止時生成的一個文件,記錄了程序崩潰時的內存狀態、寄存器值、堆棧信息等關鍵數據。
在這里插入圖片描述

exitCode = (status >> 8) & 0xFF; //退出碼
exitSignal = status & 0x7F;      //退出信號//or 使用系統定義的宏正常退出:
WIFEXITED(status):若為真,表示子進程正常退出。
WEXITSTATUS(status):獲取子進程的退出碼(即exit(code)中的code)。信號終止:
WIFSIGNALED(status):若為真,表示子進程被信號終止。
WTERMSIG(status):獲取導致終止的信號編號(如SIGKILL對應9)。

總的來說,系統為什么要進行進程等待:

  • 僵尸進程無法被kill -9信號殺死(無法殺掉一個已經死掉的進程)殺死,需要通過進程等待來殺掉進程。
  • 需要通過進程等待獲得子進程的退出情況(退出碼)

3.2 進程等待的兩個系統調用接口

3.2.1 wait()

wait函數的作用是讓父進程等待子進程結束。調用wait的時候,父進程會被阻塞,直到有一個子進程結束。然后wait會返回結束的子進程的PID,并且通過參數status來傳遞子進程的退出狀態。

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);//返回值:成功返回被等待進程pid,失敗返回-1。
參數:輸出型參數,獲取子進程退出狀態,不關心則可以設置成為NULL

如果有多個子進程,父進程每次調用wait只能處理一個,所以可能需要循環調用直到所有子進程都被回收,否則可能會有僵尸進程殘留。

3.2.2 waitpid()

waitpid函數更靈活。它的參數中可以指定要等待的子進程的PID,或者用-1表示等待任意子進程,類似wait。另外,waitpid還可以設置選項,比如WNOHANG,這樣父進程不會被阻塞,可以立即返回檢查是否有子進程結束。這在需要父進程同時處理其他任務的時候很有用,避免阻塞。

pid_ t waitpid(pid_t pid, int *status, int options);
//返回值:當正常返回的時候waitpid返回收集到的子進程的進程ID;如果設置了選項WNOHANG,而調用中waitpid發現沒有已退出的子進程可收集,則返回0;如果調用中出錯,則返回-1,這時errno會被設置成相應的值以指示錯誤所在;
//參數:pid:Pid=-1,等待任一個子進程。與wait等效。Pid>0.等待其進程ID與pid相等的子進程。status:WIFEXITED(status): 若為正常終止子進程返回的狀態,則為真。(查看進程是否是正常退出)WEXITSTATUS(status): 若WIFEXITED非零,提取子進程退出碼。(查看進程的退出碼)options:WNOHANG: 若pid指定的子進程沒有結束,則waitpid()函數返回0,不予以等待。若正常結束,則返回該子進程的ID。

區別

那wait和waitpid的區別主要在哪兒呢?

參數waitwaitpid
指定進程? 只能等任意? 可指定PID
阻塞控制? 強制等待? 支持非阻塞
狀態獲取? 基礎信息? 詳細信息

如果子進程永遠在執行,父進程wait會一直在等待子進程退出,在等待期間,父進程不能做任何事情,這種等待叫做阻塞等待 (回憶阻塞狀態,scanf會等待硬件資源,這個例子是等待軟件資源)

除了可以指定PID和選項之外,waitpid可以更精確地控制要等待哪個子進程,以及是否阻塞。比如,當父進程有多個子進程時,如果使用wait,只能按任意順序處理結束的子進程,而waitpid可以選擇等待特定的子進程,或者以非阻塞方式輪詢WNOHANG子進程狀態。

舉個例子,假設父進程創建了三個子進程,然后想要等待第二個子進程結束,這時候就可以用waitpid,傳入第二個子進程的PID作為參數。或者,如果父進程不想阻塞,可以設置WNOHANG選項,這樣如果沒有子進程結束,waitpid會立即返回0,而不會讓父進程掛起。

那如何正確使用這些函數呢?

比如,父進程fork之后,子進程可能執行不同的任務,父進程需要收集它們的退出狀態。用wait的話,父進程會阻塞直到有子進程結束,然后處理。而用waitpid的話,可以更靈活,比如循環調用waitpid(-1, &status, WNOHANG)來非阻塞地收集所有已結束的子進程,避免僵尸進程的產生,同時父進程可以做其他事情。

關于非阻塞輪詢方式需要注意:
非阻塞輪詢方式WNOHANG,可以做自己的事情

  1. 父進程順帶做自己事情的時候,這個任務不能太重,因為等待子進程退出信息才是主要任務
  2. 若子進程先于父進程任務退出,那么等待一會兒再回收也是可以的,并不是立即需要回收子進程。
  3. 通過進程等待,可以保證父進程是最后一個退出的進程,這意味著父進程創建的所有子進程已被回收。
//wait
int status;
pid_t pid = fork();
if (pid == 0) {// 子進程執行任務后退出//while(1){}   若子進程不退出,那么父進程wait阻塞等待exit(42);
} else {wait(&status);  // 父進程阻塞等待子進程結束if (WIFEXITED(status)) {printf("子進程退出碼: %d\n", WEXITSTATUS(status));  // 輸出42}
}//waitpid
int status;
pid_t child_pid = fork();
if (child_pid == 0) {// 子進程任務//while(1){} 可以通過WNOHANG觸發非阻塞輪詢方式exit(3);
} else {// 父進程非阻塞等待特定子進程while (waitpid(child_pid, &status, WNOHANG) == 0) {printf("子進程未結束,父進程繼續工作...\n");sleep(1);}if (WIFEXITED(status)) {printf("子進程退出碼: %d\n", WEXITSTATUS(status));  // 輸出3}
}

四、進程程序替換

進程程序替換是Linux系統中一個重要的概念,它允許一個進程用另一個程序完全替換當前的執行內容,同時保留進程的基本屬性(如PID、文件描述符等)。這一過程通過exec系列函數實現,這些函數能夠加載新的程序映像到當前進程中,從而改變進程的行為。調用exec并不創建新進程,所以調用exec前后該進程的pid并未改變。

4.1 進程替換原理(單進程)

之前了解到一個進程執行的過程是,首先系統創建該進程的PCB并分配進程地址空間(虛擬內存),創建映射物理內存的頁表。進程先將存儲在磁盤上的代碼塊和數據塊加載至物理內存后開始執行,運行到execl函數處,由于ls指令也是存放在磁盤上的,進程替換就非常簡單地用ls指令的代碼塊和數據塊替換掉進程的代碼塊和數據塊,再將進程從ls指令的main函數重新執行,就達到了進程切換的目的。

int main()
{printf("before\n");execl("/usr/bin/ls","ls","-a",NULL);printf("after\n");//無法執行after,因為已被替換return 0;
}

4.2 多進程版程序替換效果——驗證程序替換接口

int main()
{pid_t id = fork();if(id == 0){// 子進程執行進程替換//sleep(5)printf("before: i am a process,pid: %d, ppid: %d\n",getpid(),getppid());// 要執行的程序 、 怎樣執行該程序 、 ...為可變參數列表execl("/usr/bin/ls","ls","-a","-l",NULL);//這類方法的標準寫法//execl("/usr/bin/top","top",NULL);//execv("usr/bin/ls",myargv);//execl("./otherExec","otherExec",NULL);printf("after: i am a process,pid: %d, ppid: %d\n",getpid(),getppid());exit(0);//防止子進程繼續運行后續代碼}//父進程pid_t ret = waitpid(id,NULL,0);if(ret > 0){printf("等待子進程返回成功,father pid: %d, ret id: %d\n",getpid(),ret);}sleep(5);return 0;
}

在這里插入圖片描述
現象:程序打印before,等待五秒后切換ls進程執行,ls執行完畢瞬間waitpid接收到子進程退出信號,遂執行父進程下的打印操作,等待五秒后程序退出。

我們知道父子進程是獨立的兩塊進程地址空間,且存在寫時拷貝技術,所以子進程在替換進程的時候,是不會影響到父進程的。

寫時拷貝在修改數據時生效,替換了ls的數據塊可以理解,但代碼塊存放在常量區按理來說不應該會被修改,所以不應該發生寫時拷貝,但代碼塊不發生寫時拷貝,豈不是就會影響到父進程的執行?
答:系統層面上寫時拷貝不僅發生在數據區,也發生在代碼區,用戶無法修改代碼區的數據,但操作系統需要寫入ls代碼至父子進程,由于這塊代碼區是父子共享的且只讀,所以仍然發生了寫時拷貝。

程序替換有沒有創建新的進程?
很明顯是沒有,這一點在 ps ajx指令可以看到,并沒有額外的進程被創建,只是修改了原PCB等結構體的一些字段。但系統是如何做到替換呢?
exec系統調用的步驟是:加載新程序到內存,替換原有代碼段和數據段,調整堆棧,重置PC等寄存器,最后跳轉到新程序的入口點(main)。
從進程地址空間角度來看,每個進程由用戶地址空間與內核空間構成,在替換時,會保留內核結構,之是將新程序的代碼和數據加載到當前進程的用戶地址空間(直接覆蓋),這一操作只需通過改變文件描述符表就可以做到替換,不創建新的進程是因為內核在執行替換時是復用了原本的內核數據結構(PCB信息),并且只是更改映射關系,重新創建進程開銷巨大,這也就是exec與fork函數的區別之一。

CPU如何知道程序的入口地址?
Linux系統下,在編譯時會產生一個程序頭表,該表中存放著可執行文件的代碼段和數據段的加載位置,在執行進程替換后,程序頭表也會被替換,但同時,程序計數器PC的值也會被重置頭表的入口地址,根據偏移量,PC就能夠找到新程序的入口地址了。

多進程替換的特點

  • 替換后,進程的用戶空間代碼和數據被完全替換,新程序從其main函數開始執行。
  • 進程的PID保持不變,但代碼段、數據段、堆和棧會被替換。
  • 替換成功后,原進程的后續代碼不會執行,只有在替換失敗時才會繼續執行

4.3 進程替換的接口

//庫函數 man 3int execl(const char *path, const char *arg, ...);//路徑+參數列表,參數逐個傳遞,以NULL結尾int execlp(const char *file, const char *arg, ...);//文件名+參數列表,自動在PATH中查找int execle(const char *path, const char *arg, ...,char *const envp[]);//可自定義環境變量(通過envp數組傳遞)int execv(const char *path, char *const argv[]);//路徑+參數數組,參數通過數組傳遞int execvp(const char *file, char *const argv[]);//文件名+參數數組,自動在PATH環境變量中查找可執行文件

exec系列函數:本質是一個加載器

環境變量是什么時候給進程的?
環境變量也是數據,創建子進程的時候環境變量就已經被子進程繼承下去了(進程地址空間有一部分為進程環境變量),于是即使不寫main函數中的環境變量參數表,系統也會找到進程的環境變量,替換進程后,環境變量不變。
子進程可以新增自己的環境變量信息(putenv),再往后的子進程可以繼承它的環境變量。傳遞自定義環境變量列表時,原環境變量會被替換。

//系統調用接口
//以上六個庫函數接口實現都會調用這一接口int execve(const char *path, char *const argv[], char *const envp[])

總結

本文篇幅較大,設計知識點眾多,所以有幾個點并沒有深入討論,如核心轉儲、exel接口函數中的環境變量表如何使用等,這些內容會在后續學習中逐漸補全。

👍 ?感謝各位大佬觀看。如果本文有幫助,請點贊收藏支持~

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

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

相關文章

基于Redis實現短信防轟炸的Java解決方案

基于Redis實現短信防轟炸的Java解決方案 前言 在當今互聯網應用中&#xff0c;短信驗證碼已成為身份驗證的重要手段。然而&#xff0c;這也帶來了"短信轟炸"的安全風險 - 惡意用戶利用程序自動化發送大量短信請求&#xff0c;導致用戶被騷擾和企業短信成本激增。本…

【后端開發】Spring MVC-常見使用、Cookie、Session

文章目錄 代碼總結初始化--RestController、RequestMapping傳遞參數單參數多參數 傳遞對象后端參數重命名&#xff08;后端參數映射&#xff09;--RequestParam必傳參數設置非必傳參數 傳遞數組傳遞集合傳遞JSON數據JSON語法JSON格式轉換JSON優點傳遞JSON對象 獲取URL中參數--P…

青少年編程考試 CCF GESP Python七級認證真題 2025年3月

Python 七級 2025 年 03 月 題號 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 答案 B C A B B A A B C A B B A B A 1 單選題&#xff08;每題 2 分&#xff0c;共 30 分&#xff09; 第 1 題 下列哪個選項是python中的關鍵字&#xff1f; A. function B. class C. method D. object…

Vue 框架組件間通信方式

組件間通信方式 不管是 vue2 還是 vue3&#xff0c;組件通信方式很重要&#xff0c;以下是常見的幾種通信方式&#xff1a; props&#xff1a;可以實現父子組件、子父組件、甚至兄弟組件通信自定義事件&#xff1a;可以實現子父組件通信全局事件總線 $bus&#xff1a;可以實現…

SpringBoot學生成績管理系統設計與實現

概述 幽絡源本次分享的基于SpringBoot的學生成績管理系統項目&#xff0c;采用主流的Java技術棧開發&#xff0c;實現了從學生信息管理到成績統計分析的全流程數字化管理。 主要內容 管理員功能模塊 ??學生信息管理??&#xff1a;維護學生基本信息檔案&#xff0c;支持…

青少年編程與數學 02-016 Python數據結構與算法 01課題、算法

青少年編程與數學 02-016 Python數據結構與算法 01課題、算法 一、算法的定義二、算法的設計方法1. 分治法2. 動態規劃法3. 貪心算法4. 回溯法5. 迭代法6. 遞歸法7. 枚舉法8. 分支定界法 三、算法的描述方法1. **自然語言描述**2. **流程圖描述**3. **偽代碼描述**4. **程序設計…

Java 實現冒泡排序:[通俗易懂的排序算法系列之二]

引言 大家好!歡迎來到我的排序算法系列第二篇。今天,我們將學習另一種非常基礎且廣為人知的排序算法——冒泡排序 (Bubble Sort)。 冒泡排序的名字非常形象,它模擬了水中氣泡上升的過程:較小(或較大)的元素會像氣泡一樣,通過不斷交換,逐漸“浮”到數組的一端。 什么是…

struct結構體、union聯合體和枚舉

目錄 一、結構體的聲明和使用 1.1 結構體正常聲明和創建 1.2 結構體特殊聲明 1.3 結構體的自引用 二、結構體內存對齊 2.1 對齊規則 2.2 #pragma修改 三、結構體傳參 四、結構體位段 4.1 位段內存分配 4.2 位段內存應用 五、結構體中的柔性數組概念 六、union聯合…

大模型本地部署系列(2) Ollama部署DeepSeek-R1

成功運行截圖 部署步驟 我們進入到ollama的官網&#xff1a; Ollama?ollama.com/?編輯 找到上方的Models &#xff0c;然后點擊 此時會跳轉到模型列表頁面&#xff1a; 點擊 deepseek-r1 鏈接進去&#xff0c;此時我們會看到下拉框中有各個版本的大模型&#xff0c;越往后…

繪制動態甘特圖(以流水車間調度為例)

import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np from matplotlib import cm# 中文字體配置&#xff08;必須放在所有繪圖語句之前&#xff09; plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] Fa…

PyTorch實現線性回歸的基礎寫法與封裝API寫法

目錄 1. 基礎寫法 1.1導包 2.2加載讀取數據 2.3原始數據可視化(畫圖顯示) 2.4線性回歸的(基礎)分解寫法 2.5定義訓練過程 2.PyTorch實現 線性回歸的封裝寫法(實際項目中的常用寫法) 2.1創建線性回歸模型 2.2定義損失函數 2.3定義優化器 2.4定義訓練過程 1…

python 常用的6個爬蟲第三方庫

Python中有非常多用于網絡數據采集的庫&#xff0c;功能非常強大&#xff0c;有的用于抓取網頁&#xff0c;有的用于解析網頁&#xff0c;這里介紹6個最常用的庫。 1. BeautifulSoup BeautifulSoup是最常用的Python網頁解析庫之一&#xff0c;可將 HTML 和 XML 文檔解析為樹形…

基于BP神經網絡的雜草智能識別系統(雜草識別、Python項目)

基于BP神經網絡的雜草智能識別系統 項目介紹 本項目是一個基于PyQt5和BP神經網絡的雜草智能識別系統。系統通過圖像處理和神經網絡技術&#xff0c; 能夠識別8種不同的雜草類別。用戶可以通過上傳圖片&#xff0c;系統會自動識別圖片中的雜草類別&#xff0c;并顯示識別結果和…

Python3筆記之號稱替代pip的uv包管理器

uv是什么&#xff1f; uv&#xff0c;這是一個由 Astral 團隊開發的極快速的Python包和項目管理工具&#xff0c;用Rust語言編寫。它集成了多種功能&#xff0c;旨在替代pip、pip-tools、pipx、poetry、pyenv、twine、virtualenv等多個工具&#xff0c;提供更高效、更全面的Py…

IT管理思路

甲方CIO和IT管理者-如何做好組織級IT能力提升_嗶哩嗶哩_bilibili

ChatGPT的GPT-4o創建圖像Q版人物提示詞實例展示

最近感覺GPT-4o發布的新功能真的強大&#xff0c;所以總結了一些提示詞分享給大家&#xff0c;大家可以去試試&#xff0c;玩法多多&#xff0c;可以用GPT-4o生成圖片&#xff0c;然后用可靈進行圖生視頻&#xff0c;就能去發布視頻了&#xff01;接下來和筆者一起來試試&#…

Transformer Decoder Block的幾個優化方案

寫在前面 在大型語言模型(LLM)的演進浪潮中,Transformer 架構憑借其強大的并行計算能力和對長距離依賴的出色捕捉,奠定了核心地位。然而,標準的 Transformer Decoder Block 遵循著一種相對固定的模式:先進行自注意力(Self-Attention)捕捉上下文信息,再通過前饋神經網…

五種IO模型與select和poll分別實現多路轉接

五種IO模型與select和poll分別實現多路轉接 何為IO 不論是在前面文件部分&#xff0c;還是后面的網絡部分&#xff0c;IO都是非常常見的。但是當時只是簡單對IO進行提及&#xff0c;并沒有對IO的本質進行介紹。那么到底何為IO&#xff1f;IO全稱為輸入和輸出&#xff0c;而任…

單例模式的寫法(保證線程安全)

1. 引言 1.1 什么是單例模式&#xff1f; 單例模式&#xff08;Singleton Pattern&#xff09;是一種創建型設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點。 核心思想&#xff1a;控制實例化過程&#xff0c;避免重復創建對象。 1.2 為什么…

C++ 環境設置

C++ 環境設置 引言 C++作為一種高性能的編程語言,廣泛應用于系統軟件、游戲開發、實時系統等領域。為了能夠順利進行C++編程,我們需要在計算機上配置合適的開發環境。本文將詳細講解如何在Windows、macOS和Linux系統中設置C++開發環境。 Windows系統下C++環境設置 1. 安裝…