Linux C語言 41-進程間通信IPC之共享內存

Linux C語言 41-進程間通信IPC之共享內存

本節關鍵字:C語言 進程間通信 共享內存 shared memory
相關庫函數:shmget、shmat、shmdt、shmctl

什么是共享內存?

共享內存(Shared Memory)指兩個或多個進程共享一個給定的存儲區。

共享內存的特點

  • 共享內存是最快的只用System V IPC,因為進程是直接對內存進行讀寫;
  • 因為多個進程可以同時操作,所以需要進程同步;
  • 信號量+共享內存通常結合在一起使用,信號量用來同步對共享內存的訪問;
  • 共享內存被創建成功后需要手動釋放,否則將持續到內核重新引導。

共享內存相關庫函數

創建或鏈接一個共享內存

當創建新的共享內存段時,其內容被初始化為零,并且其相關的數據結構shmid_ds(參見shmctl(2))被初始化如下:

  • shm_perm.uid 和shm_perm.uid 被設置為調用進程的有效用戶ID。
  • shm_perm.cgid 和shm_perm_gid 被設置為調用進程的有效組ID。
  • shm_perm.mode 的最低有效9位被設置為shmflg 的最低有效的9位。
  • shm_setsz 設置為size 的值。
  • shm_lpid、shm_natch、shm_time和shm_dtime 設置為0。
  • shm_time 設置為當前時間。

如果共享內存段已經存在,則會驗證權限,并檢查它的銷毀標記是否有效。

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
key_t ftok(const char *pathname, int proj_id); // 前文消息隊列中已經介紹過,這里就不展開介紹了
int shmget(key_t key, size_t size, int shmflg);
/**
@brief 分配共享內存段。shmget()返回與參數key的值相關聯的共享內存段的標識符。如果key的值為IPC_PRIVATE或key不是IPC_PRIVATE,不存在與該密鑰對應的共享內存段,并且在shmflg中指定了IPC_CREAT,則會創建一個新的共享內存分段,其大小等于四舍五入到PAGE_SIZE的倍數。如果shmflg同時指定了IPC_CREAT和IPC_EXCL,并且key的共享內存段已經存在,那么shmget()將失敗,errno設置為EEXIST。(這類似于組合O_CREAT | O_EXCL對open(2)的效果。)
@param key 進程間通信的鍵值(密鑰),是ftok()的返回值
@param size 該共享內存的字節長度
@param shmflg 表示函數的行為及共享內存的權限,取值如下:IPC_CREAT    如果不存在就創建IPC_EXCL    如果存在則返回失敗mode_flags(最低有效9位),指定授予所有者、組和世界的權限。這些位具有與open(2)的模式自變量相同的格式和含義。目前,系統未使用執行權限。SHM_HUGETLB 自Linux 2.6起)使用“巨大的頁面”分配段。有關更多信息,請參閱內核源文件Documentation/vm/hugetlbpage.txt。SHM_NORESERVE (自Linux 2.6.15起)此標志的作用與mmap(2)MAP_NORESERVE標志相同。不要為該段保留交換空間。當保留交換空間時,可以保證可以修改段。當交換空間沒有保留時,如果沒有可用的物理內存,則可能會在寫入時獲得SIGSEGV。另請參閱proc(5)中文件/proc/sys/vm/overcommit_memory的討論。
@return 成功返回有效的貢獻內存標識符shmid,失敗返回-1,并設置錯誤碼errno錯誤碼errno的類型:
EACCES        用戶沒有訪問共享內存段的權限,也沒有CAP_IPC_OWNER功能。
EEXIST        指定了IPC_CREAT | IPC_EXCL,并且該段存在。
EINVAL        要創建一個新的段,其大小<SHMMIN或size>SHMMAX,或者不創建新的段、存在一個具有給定鍵的段,但大小大于該段的大小。
ENFILE        已達到打開文件總數的系統限制。
ENOENT        給定key不存在分段,并且未指定IPC_CREAT。
ENOMEM        無法為段開銷分配內存。
ENOSPC        已獲取所有可能的共享內存ID(SHMMNI),或者分配所請求大小的段將導致系統超過共享內存的系統范圍限制(SHMALL)。
EPERM         指定了SHM_HUGETLB標志,但調用方沒有特權(不具有CAP_IPC_LOCK功能)。NOTES
IPC_PRIVATE不是標志字段,而是key_t類型。如果這個特殊值用于key,則系統調用將忽略shmflg的除最低有效9位之外的所有內容,并創建一個新的共享內存段。
以下對共享內存段資源的限制會影響shmget()調用:
SHMALL        系統范圍內共享內存頁的最大值(在Linux上,可以通過/proc/sys/kernel/SHMALL讀取和修改此限制)。
SHMMAX        共享內存段的最大大小(以字節為單位):取決于策略(在Linux上,可以通過/proc/sys/kernel/SHMMAX讀取和修改此限制)。
SHMMIN        共享內存段的最小大小(以字節為單位):取決于實現(當前為1字節,但PAGE_size是有效的最小大小)。
SHMMNI        系統范圍內共享內存段的最大數量:取決于實現(目前為4096個,在Linux 2.3.99之前為128個;在Linux上,可以通過/proc/sys/kernel/SHMMNI讀取和修改此限制)。
該實現對每個進程的共享內存段的最大數量(SHMSEG)沒有特定限制。
*/
將共享內存映射到進程內存

一個成功的shmat()調用將更新與共享內存段相關聯的shmid_ds結構的成員(請參見shmctl(2)),如下所示:

  • shm_time 設置為當前時間。
  • shm_lpid 設置為調用進程的進程ID。
  • shm_natch 增加1。
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
/**
@brief shmat()將shmid標識的共享內存段附加到調用進程的地址空間。附加地址由shmaddr根據以下條件之一指定:如果shaddr為NULL,系統會選擇一個合適的(未使用的)地址來附加段。如果shaddr不為NULL,并且在shmflg中指定了SHM_RND,則附加發生在等于shaddr的地址處,四舍五入到SHMLBA的最近倍數。否則,shaddr必須是發生附加的頁面對齊地址。如果在shmflg中指定了SHM_RDONLY,則附加該段進行讀取,并且進程必須具有該段的讀取權限。否則,將附加段進行讀寫操作,并且進程必須具有該段的讀寫權限。不存在只寫共享內存段的概念。
@param shmid 共享內存的標識符,是shmget()的成功返回值
@param shmaddr 共享內存映射地址(為NULL則系統自動指定),一般使用NULL
@param shmflg 共享內存端的訪問權限和映射條件(一般設置為0),具體取值如下:0 共享內存具有可讀可寫權限SHM_RDONLY 只讀SHM_RND shmaddr非空時才有效
@return 成功返回附加的共享內存段的地址;失敗返回-1,并設置錯誤碼errno錯誤碼errno的類型:
EACCES        調用進程不具有所請求的附加類型所需的權限,也不具有CAP_IPC_OWNER功能。
EIDRM         shmid指向一個已刪除的標識符。
EINVAL        無效的shmid值、未對齊(即未對齊頁面且未指定SHM_RND)或無效的shaddr值,或者無法在shaddr處附加段,或者指定了SHM_REMAP且shaddr為NULL。
ENOMEM        無法為描述符或頁表分配內存。
*/#### 解除共享內存的映射
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
/**
@brief shmdt()從調用進程的地址空間中分離位于shaddr指定地址的共享內存段。
要分離的段當前必須附加等于附加shmat()調用返回值的shaddr。在成功調用shmdt()時,系統會更新與共享內存段相關聯的shmid_ds結構的成員,如下所示:shm_dtime 設置為當前時間。shm_lpid  設置為調用進程的進程ID。shm_natch 遞減一。如果它變為0并且該段被標記為刪除,則該段被刪除。
@param shmaddr 共享內存的參數地址
@return 成功返回0,失敗返回-1,并設置錯誤碼errno錯誤碼errno的類型:
EINVAL        shaddr上沒有附加共享內存段;或者,shaddr沒有在頁面邊界上對齊。
*/
控制共享內存
#include <sys/ipc.h>
#include <sys/shm.h>struct ipc_perm 
{key_t          __key;    // shmget(2)提供的密鑰uid_t          uid;      // 所有者的有效UIDgid_t          gid;      // 所有者的有效GIDuid_t          cuid;     // 創建者的有效UIDgid_t          cgid;     // 創建者的有效GIDunsigned short mode;     // 權限+SHM_DEST和SHM_LOCKED標志unsigned short __seq;    // 序列號碼
};struct shmid_ds 
{struct ipc_perm shm_perm;    // 所有權和權限size_t          shm_segsz;   // 段大小(字節)time_t          shm_atime;   // 上次連接時間time_t          shm_dtime;   // 上次分離時間time_t          shm_ctime;   // 上次修改時間pid_t           shm_cpid;    // 創建者進程PIDpid_t           shm_lpid;    // 上次執行shmat(2)或shmdt(2)的進程PIDshmatt_t        shm_nattch;  // 當前附件數量...
};struct  shminfo 
{unsigned long shmmax; // 共享內存最大分段長度unsigned long shmmin; // 共享內存最小分段長度,總為1unsigned long shmmni; // 共享內存最大分段數unsigned long shmseg; // 進程可以附加的最大段數;內核中未使用unsigned long shmall; // 系統范圍內共享內存的最大頁數// shmmni、shmmax和shmall設置可以通過相同名稱的/proc文件進行更改;有關詳細信息,請參見proc(5)。
};struct shm_info
{int           used_ids;           // # of currently existing segmentsunsigned long shm_tot;            // Total number of shared memory pagesunsigned long shm_rss;            // # of resident shared memory pagesunsigned long shm_swp;            // # of swapped shared memory pagesunsigned long swap_attempts;      // Unused since Linux 2.4unsigned long swap_successes;     // Unused since Linux 2.4
};int shmctl(int shmid, int cmd, struct shmid_ds *buf);
/**
@brief 獲取和設置消息隊列的屬性
@param shmid 共享內存的標識符
@param cmd 函數功能的控制,取值如下:IPC_STAT        將信息從與shmid關聯的內核數據結構復制到buf指向的shmid_ds結構中。調用方必須具有對共享內存段的讀取權限。IPC_SET         將buf指向的shmid_ds結構的一些成員的值寫入與該共享內存段相關聯的內核數據結構,同時更新其shm_time成員。可以更改以下字段:shm_perm.uid、shm_perm_gid和(shm_per.mode的最低有效9位)。調用進程的有效uid必須與共享內存段的所有者(shm_erm.uid)或創建者(shm_term.cuid)匹配,或者調用方必須具有特權。IPC_RMID        標記要銷毀的段。只有在最后一個進程將該段分離后(即,當關聯結構shmid_ds的shm_natch成員為零時),該段才會被實際銷毀。調用方必須是所有者或創建者,或者具有特權。如果某個段已標記為要銷毀,則將設置IPC_STAT檢索到的相關數據結構中的SHM_perm.mode字段的(非標準)SHM_DEST標志。調用方必須確保一個段最終被銷毀;否則,其在中出現故障的頁面將保留在內存或交換中。IPC_INFO        (特定于Linux)返回有關buf指向的結構中的系統范圍共享內存限制和參數的信息。如果定義了_GNU_SOURCE功能測試宏,則該結構的類型為shminfo(因此,需要強制轉換),在<sys/shm.h>中定義: struct shminfo;(結構內容及注釋在上方展示)SHM_INFO        (特定于Linux)返回一個shm_info結構,其字段包含有關共享內存所消耗的系統資源的信息。如果定義了_GNU_SOURCE功能測試宏,則在<sys/shm.h>中定義此結構:struct shm_info;(結構內容及注釋在上方展示)SHM_STAT        (特定于Linux)返回與IPC_STAT相同的shmid_ds結構。但是,shmid參數不是段標識符,而是內核內部數組的索引,該數組維護系統上所有共享內存段的信息。調用方可以阻止或允許使用以下cmd值交換共享內存段:SHM_LOCK        (特定于Linux)防止交換共享內存段。調用方必須在啟用鎖定后所需的任何頁面中出錯。如果某個段已被鎖定,則將設置IPC_STAT檢索到的相關數據結構中的SHM_perm.mode字段的(非標準)SHM_locked標志。SHM_UNLOCK      (特定于Linux)解鎖分段,允許將其交換出去。在2.6.10之前的內核中,只有特權進程可以使用SHM_LOCK和SHM_UNLOCK。由于內核2.6.10,如果非特權進程的有效UID與段的所有者或創建者UID匹配,并且(對于SHM_LOCK)要鎖定的內存量在RLIMIT_MEMLOCK資源限制范圍內,則該進程可以使用這些操作(請參見setrlimit(2))。@param buf  shmid_ds 數據類型的地址,用來存放或修改共享內存的屬性。
@return 成功的IPC_INFO或SHM_INFO操作返回內核內部數組中使用次數最多的條目的索引,該數組記錄了有關所有共享內存段的信息。(此信息可與重復的SHM_STAT操作一起使用,以獲得有關系統上所有共享內存段的信息。)成功的SHM_TAT操作將返回共享內存段(其索引在shmid中給出)的標識符。其他操作成功后返回0。失敗返回-1,并設置錯誤碼errno錯誤碼errno的類型:
EACCES        IPC_STAT或SHM_STAT被請求,并且SHM_perm.mode不允許對shmid進行讀取訪問,并且調用進程不具有CAP_IPC_OWNER功能。
EFAULT        參數cmd的值為IPC_SET或IPC_STAT,但buf指向的地址不可訪問。
EIDRM         shmid指向一個已刪除的標識符。
EINVAL        shmid不是有效的標識符,或者cmd不是有效命令。或者:對于SHM_STAT操作,shmid中指定的索引值引用了當前未使用的數組槽。
ENOMEM        (在2.6.9之后的內核中),指定了SHM_LOCK,并且要鎖定的段的大小意味著鎖定的共享內存段中的總字節數將超過調用進程的真實用戶ID的限制。此限制由RLIMIT_MEMLOCK軟資源限制定義(請參閱setrlimit(2))。
EOVERFLOW    嘗試IPC_STAT,但GID或UID值太大,無法存儲在buf指向的結構中。
EPERM        嘗試IPC_SET或IPC_RMID,并且調用進程的有效用戶ID不是創建者(在shm_perm.cuid中找到)或所有者(在shr_perm.uid中找到)的ID,并且進程沒有特權(Linux:不具有CAP_SYS_ADMIN功能)。或者(在2.6.9之前的內核中),指定了SHM_LOCK或SHM_UNLOCK,但進程沒有特權(Linux:沒有CAP_IPC_LOCK功能)。(從Linux 2.6.9開始,如果RLIMIT_MEMLOCK為0并且調用方沒有特權,也可能發生此錯誤。)NOTES
ipcs(8)程序使用IPC_INFO、SHM_STAT和SHM_INFO操作來提供有關所分配資源的信息。將來,這些文件可能會被修改或移動到/proc文件系統接口。Linux允許進程使用shmctl(IPC_RMID)附加(shmat(2))已標記為刪除的共享內存段。此功能在其他Unix實現中不可用;可移植應用程序應避免依賴它。
結構shmid_ds中的各種字段在Linux 2.2下被鍵入為短字段,而在Linux 2.4下則變為長字段。為了利用這一點,在glibc-2.1.91或更高版本下重新編譯就足夠了。(內核通過cmd中的IPC_64標志來區分新舊調用。)
*/

共享內存例程

/*** 共享內存使用例程,創建、連接、寫、讀、斷開連接、刪除* 目前未增加線程安全措施,后期可以增加互斥鎖等*/#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SHM_FULL            1
#define SHM_LINES_MAX       10
#define SHM_LINE_LEN_MAX    128typedef struct 
{int  w_idx, full;char msg[SHM_LINES_MAX][SHM_LINE_LEN_MAX];int  len[SHM_LINES_MAX];
} SHM;void shmwrite(SHM *shm, const char *msg, size_t len);
char *shmread(SHM *shm);int main() 
{key_t shmid;SHM *shmaddr = NULL;char message[SHM_LINE_LEN_MAX];// 創建一個新的共享內存段,也可自行指定key值(將IPC_PRIVARE換成其它值,例如:6565656)shmid = shmget(IPC_PRIVATE, sizeof(SHM), IPC_CREAT | 0666);if (shmid == -1) {perror("shmget");exit(EXIT_FAILURE);}// 連接到共享內存段shmaddr = shmat(shmid, NULL, 0);if (shmaddr == (void *)-1) {perror("shmat");exit(EXIT_FAILURE);}printf("shared memory: shmid[%d], address[%p]\n", shmid, shmaddr);// 對共享內存進行讀寫等操作...while (shmaddr->full != SHM_FULL){printf("please input your message: ");bzero(message, sizeof(message));scanf("\n%[^\n]", message); //注意嘗試思考和直接使用 %s的區別哦^!^shmwrite(shmaddr, message, strlen(message));printf("reading shared memory data...\n");shmread(shmaddr);// 此過程中可以在新開命令窗口中使用 ipcs -m 查看新建共享內存的相關信息}printf("shared memory will be deleted in 5 seconds\n");sleep(5);// 從共享內存分離if (shmdt(shmaddr) != 0) {perror("shmdt");exit(EXIT_FAILURE);}// 刪除共享內存段if (shmctl(shmid, IPC_RMID, NULL) != 0) {perror("shmctl");exit(EXIT_FAILURE);}// 此時再使用 ipcs -m 查看創建的共享內存已經不存在了printf("shared memory deleted: shmid[%d], address[%p]\n", shmid, shmaddr);return 0;
}void shmwrite(SHM *shm, const char *msg, size_t len)
{if (shm->full == SHM_FULL)return;strncpy(shm->msg[shm->w_idx], msg, len);shm->len[shm->w_idx] = len;shm->w_idx++;if (shm->w_idx == SHM_LINES_MAX)shm->full = SHM_FULL;
}char *shmread(SHM *shm)
{int i, count;if (shm->w_idx == 0){printf("share memory is empty\n");return;}count = shm->w_idx;for (i=0; i<count; i++){printf("[%d]: %s\n", i, shm->msg[i]);}return shm->msg[count];
}

提示:先做內容框架梳理,后期進行完善補充!

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

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

相關文章

InnoDB Architecture MySQL 5.7 vs 8.0

innodb-architecture-5-7 innodb-architecture-8-0 圖片均來源于MySQL官網

【Vue】props與$emit的簡單理解

Vue組件 組件是Vue中不可或缺的一個功能&#xff0c;它可以將一個頁面劃分為多個獨立的內部組件&#xff0c;方便代碼的管理。 定義組件 <body><div id"App"><bcomp></bcomp></div><script>const app Vue.createApp({})cons…

【2023傳智杯-新增場次】第六屆傳智杯程序設計挑戰賽AB組-ABC題復盤解題分析詳解【JavaPythonC++解題筆記】

本文僅為【2023傳智杯-第二場】第六屆傳智杯程序設計挑戰賽-題目解題分析詳解的解題個人筆記,個人解題分析記錄。 本文包含:第六屆傳智杯程序設計挑戰賽題目、解題思路分析、解題代碼、解題代碼詳解 文章目錄 一.前言二.賽題題目A題題目-B題題目-C題題目-二.賽題題解A題題解-…

Servlet should have a mapping

第一種可能&#xff1a; 你就是沒寫Servlet <servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 配置springMVC需要加載的配置文件--><init-par…

Android studio生成二維碼

1.遇到的問題 需要生成一個二維碼&#xff0c;可以使用zxing第三方組件&#xff0c;增加依賴。 //生成二維碼 implementation com.google.zxing:core:3.4.1 2.代碼 展示頁面 <ImageViewandroid:id"id/qrCodeImageView"android:layout_width"150dp"an…

ubuntu 如何修改主機名稱

UBUNTU 2018.04 LTS 64位 修改當前電腦的主機名稱。 操作步驟如下&#xff1a; 假設你的主機名為AAAAA &#xff0c; 打算修改為BBBBB。開機進入桌面。 打開一個終端。命令行下&#xff0c;使用vi /etc/hostname指令&#xff0c;編輯主機名稱。將hostname文件里的AAAAA改為BB…

【Linux】echo命令使用

?echo命令 功能是在顯示器上顯示一段文字&#xff0c;一般起到一個提示的作用。此外&#xff0c;也可以直接在文件中寫入要寫的內容。也可以用于腳本編程時顯示某一個變量的值&#xff0c;或者直接輸出指定的字符串。 ? 著者 由布萊恩福克斯和切特拉米撰寫。 語法 echo […

Flum--環境搭建實驗

1.解壓flum安裝包 解壓到/opt/module下&#xff1a; tar -zxvf /opt/software/apache-flume-1.9.0-bin.tar.gz -C /opt/module/ 2.修改flum名字&#xff1a; mv /opt/module/apache-flume-1.9.0-bin /opt/module/flume 3.將lib文件夾下的guava-11.0.2.jar刪除以兼容Hadoop…

圖像萬物分割——Segment Anything算法解析與模型推理

一、概述 在視覺任務中&#xff0c;圖像分割任務是一個很廣泛的領域&#xff0c;應用于交互式分割&#xff0c;邊緣檢測&#xff0c;超像素化&#xff0c;感興趣目標生成&#xff0c;前景分割&#xff0c;語義分割&#xff0c;實例分割&#xff0c;泛視分割等。 交互式分割&am…

設計模式之結構型模式(適配器、橋接、組合、享元、裝飾者、外觀、代理)

文章目錄 一、結構型設計模式二、適配器模式三、橋接模式四、組合模式五、享元模式六、裝飾者模式七、外觀模式八、代理設計模式 一、結構型設計模式 這篇文章我們來講解下結構型設計模式&#xff0c;結構型設計模式&#xff0c;主要處理類或對象的組合關系&#xff0c;為如何…

【已解決】ModuleNotFoundError: No module named ‘IPython‘

問題描述 Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named IPython 解決方法 pip install ipython 完結撒花 我并不想穿過荊棘去到黎明&#xff0c;我猜也沒有人會想

proftpd安全加固:禁用匿名登錄

其實&#xff0c;proftpd默認是禁止匿名登錄的。今天我們反其道&#xff0c;研究一下如何開啟匿名登錄。清楚了怎么破防&#xff0c;才能更好得防。 查看/etc/proftpd.conf 配置文件&#xff1a; # A basic anonymous configuration, with an upload directory # Enable this…

計算機設備管理器如何看內存,怎么查看電腦配置信息?3種方法,讓你掌握電腦全部信息!...

轉載&#xff1a;https://blog.csdn.net/weixin_35849957/article/details/118512756?spm1001.2014.3001.5502 原標題&#xff1a;怎么查看電腦配置信息&#xff1f;3種方法&#xff0c;讓你掌握電腦全部信息&#xff01; 電腦的配置決定了電腦性能高低以及運行速度。而電腦…

Emacs之Plantuml用于復雜UML類圖(Markdown用于簡單類圖)(一百三十二)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

python主流開發工具排名,python開發工具有哪些

本篇文章給大家談談python的開發工具軟件有哪些&#xff0c;以及python主流開發工具排名&#xff0c;希望對各位有所幫助&#xff0c;不要忘了收藏本站喔。 python中用到哪些軟件 一、Python代碼編輯器1、sublime Textsublime Text是一款非常流行的代碼編輯器&#xff0c;支持P…

STM32L051使用HAL庫操作實例(13)- 讀取IAQ-CORE-C傳感器實例

目錄 一、前言 二、傳感器參數 三、STM32CubeMX配置&#xff08;本文使用的STM32CubeMX版本為6.1.2&#xff09;例程使用模擬I2C進行數據讀取 1.MCU選型 2.使能時鐘 3.時鐘配置 4.GPIO口配置 四、配置STM32CubeMX生成工程文件 五、點擊GENERATE CODE生成工程文件 六、…

Kubersphere應用【二】Docker安裝

一、Docker安裝 1.下載Docker安裝包 【地址】Index of linux/static/stable/x86_64/ 2.上傳至服務器 # 解壓文件 tar -xvf docker-20.10.10.tgz# 將docker 目錄中的所有文件復制至/usr/bin/目錄下 cp docker/* /usr/bin 3.配置docker.service文件 vim /usr/lib/systemd/sy…

arm平臺編譯so文件回顧

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、幾個點二、回顧過程 1.上來就執行Makefile2.編譯第三方開源庫.a文件 2.1 build.sh腳本2.2 Makefile3.最終編譯三、其它知識點總結 前言 提示&#xff1a;這…

MSSQL存儲過程的功能和用法(簡明扼要)

官方文檔 存儲過程&#xff08;數據庫引擎&#xff09; - SQL Server | Microsoft Learn Transact-SQL 參考&#xff08;數據庫引擎&#xff09; - SQL Server | Microsoft Learn 定義 存儲過程可以用編程語言的方法來類比&#xff0c;有輸入輸出。區別是其使用SQL表達業務…

spring 單元測試 Junit

我是南城余&#xff01;阿里云開發者平臺專家博士證書獲得者&#xff01; 歡迎關注我的博客&#xff01;一同成長&#xff01; 一名從事運維開發的worker&#xff0c;記錄分享學習。 專注于AI&#xff0c;運維開發&#xff0c;windows Linux 系統領域的分享&#xff01; 本…