第三十三天(信號量)

非常非常非常.....的重要在共享內存的代碼里面p1.c實質是有問題lt._flag = 1;//這里先置1if(c == 'Q')sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好,%d 我系渣渣輝. %d 是兄弟就來砍我吧!!! %d",i,i+1,i+2);while(*((int *)shmptr));//如果別人沒有把上一條消息給拿走,那我就卡在這里memcpy(shmptr,&lt,sizeof(lt));//copy到共享內存  我們是想copy之后別人拿這個信息我們是想copy之后別人拿這個信息 --- copy之后你根本就沒有告訴別人copy完是什么時候那么別人就可以在你copy中途的就過來拿p2 -> lt._flag等于1了就可以拿了lt._flag等于1是在copy的時間段里面前面那個時間就會將其置1p2看到變成1了,它就可以去讀后面內容了,p2很有可能拿到了一個錯誤的內容現在我要解決這個問題lt._flag = 0;//if(c == 'Q')sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好,%d 我系渣渣輝. %d 是兄弟就來砍我吧!!! %d",i,i+1,i+2);while(*((int *)shmptr));//如果別人沒有把上一條消息給拿走,那我就卡在這里memcpy(shmptr,&lt,sizeof(lt));//copy到共享內存  我們是想copy之后別人拿這個信息*(int *)shmptr = 1;//再置1又有一個新的問題出現了,出現了p3 也操作這個共享內存,它也是往這個共享內存里面寫的p1正在寫的途中,p3過來一看 _flag == 0它也可以寫看誰搞得慢,誰慢就保留誰的信息上面不管有幾個進程在活動,不變的只有一個 --- 共享內存不變那么我可以對這個共享內存實現一個保護機制 --- 只要有進程在操作這個共享內存,別人都不能操作int flag;//這個flag在共享內存上面,有別與上面共享內存每一個進程在放在共享內存的時候都先過來看看flag的值如果flag == 0 ,我就不能訪問共享內存flag == 1,我就可以去訪問,訪問之前我先將flag調成0,然后訪問共享內存訪問完畢再調成1每一個進程在訪問之前都過來看這個flag,都遵守這個規則,那么就不會出現問題了p1 和 p2同時過來看flag的值,他們兩個同時發現flag == 1他們就去訪問這個共享內存了,這個保護機制又崩潰了要將保護機制繼續完善,誰過來訪問flag的時候其它的人都不能訪問如果你再弄一個保護的flag1,flag1又可能要成為保護的對象,這就成了一個死局了我們只需要解決不能同時過來操作flag的值 --- 原子操作可以解決(cpu產生的指令只會允許有一個進程過來操作)解決這個保護問題,并且實現原子操作的事情就是信號量解決的問題信號量就是一個以原子操作來實現的一個保鏢保證我們的共享資源有序訪問它是為了保護別人而生的,沒有保護對象就不需要信號量信號量是一種保護機制,對程序員的一個約定(程序員應該遵守,不是強制,程序員要知道如果你不遵守,你很有可能得到一個錯誤的值)    因此在并發里面信號量機制成為了必然信號量的操作流程首先實現 P操作(上鎖,上鎖的過程是原子操作)上鎖完畢,再過去訪問共享資源共享資源訪問完畢   -> 這個區域我們叫臨界區(約定:快進快出)如果你占著這個臨界區,結果你死了或者一直不進行V操作,這種情況我們叫死鎖(死鎖是一個非常嚴重的問題,我們不應該有死鎖的操作)再進行 V操作(解鎖)P操作:使其信號量遞減的操作V操作:使其信號量遞增的操作如我的flag = 1;P操作就是--flag;V操作就是++flagflag = 1 ->這種信號量我們叫互斥信號量 但是有的時候某一些共享資源支持多個進程同時訪問,那么這個時候flag > 1P操作一般我們認為是 --就可以了,但是有的時候可能一個進程需要多個資源,這個時候就不是--,它需要 -= nV操作有的時候就需要 += n信號量實現 --- 它是實現在內核上面的一個標志,對于它的操作保證了原子操作信號量有兩種System V semaphore  -> 兩種標準 此標準一般用于進程System V信號量是一個信號量集,里面有多個信號量信號量集里面的信號量可以單獨操作的,實現對于不同共享資源或者同一個共享資源需要多個信號量的保護的需求POSIX semaphore -> 此標準一般用于線程struct semid_ds {struct ipc_perm    sem_perm;     /* 權限 */__kernel_time_t    sem_otime;    /* 最后 semop 時間 */__kernel_time_t    sem_ctime;    /* 最后 semctl() 時間 */struct sem *sem_base;    /*信號量數組 */ = malloc(sizeof(struct sem) * nsems)struct sem_queue *sem_pending;    /* 等在這個信號量隊列上面的進程 */struct sem_queue **sem_pending_last;   /* 最后等的那個 */struct sem_undo    *undo;       /* 撤銷 */unsigned short sem_nsems;    /* 信號量的個數,就是 sem_base有多少個元素*/
};struct sem//單個信號量的類型
{int value;//信號量的值pid_t sempid;//最后一次進行p/v操作的進程idint semncnt;//使其增長的進程數量int semzcnt;//使其變成0的進程數量
};創建一個信號量集semget - get a System V semaphore set identifierSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);key:一個ipc key,如果你想操作同一個信號量,key必須一樣nsems:這個信號量集里面你想有幾個信號量,只有創建信號量集的時候有效打開的時候這個參數會被忽略這個數量一旦確定了,以后就不能改了semflg:標志IPC_CREAT | 權限   創建0打開一個信號量集返回值:成功返回信號集的id,失敗返回-1,同時errno被設置The  values of the semaphores in a newly created set are indeterminate.新創建出來的信號量集里面的信號量的值是不確定的所以我們需要給這些信號量馬上設置值NAMEsemctl - System V semaphore control operations控制這個信號量集
SYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(int semid, int semnum, int cmd, ...);semid:信號量集的idsemnum:信號量集里面有多個信號量,你現在要操作哪一個你是不是要給我指明從0開始   一直到 nsems - 1如果cmd表明的是操作所有的信號量,那么這個參數就被忽略了cmd:命令號IPC_STAT    復制IPC_SET     設置IPC_RMID    刪除GETALL      獲取所有GETVAL      獲取一個SETALL      設置所有SETVAL      設置一個.........(arg):根據第三個命令號來,命令不一樣,這個參數就會不一樣cmd == GETALL: 獲取所有的信號量的值因此第四個參數就需要弄一個什么樣子的東西進去,用于保存所有的信號量的值我們需要用一個unsigned short arr[nsems];//原先創建的時候nsems是多少,這里就給多少semctl(semid,0,GETALL,arr);cmd == GETVAL : 獲取單個信號量的值第二個參數為哪一個信號量第四個參數就被忽略了,獲取到的值通過返回值返回給你unsigned short value = semctl(semid,2,GETVAL);//獲取信號量集里面的第三個信號的值cmd == SETALL : 設置所有的信號量的值,第二個參數被忽略第四個參數就是unsigned short數組的首地址unsigned short arr[5] = {3,2,5,7,1};//你的信號量集里面有5個信號量semctl(semid,2,SETALL,arr);cmd == SETVAL : 設置某一個信號量的值第二個參數為哪一個信號量第四個參數就是一個int值int  value = 4;semctl(semid,1,SETVAL,value);//設置信號量集里面的第二個信號量的值為4cmd == IPC_STAT/IPC_SET  獲取或者設置信號量集頭節點的信息第四個參數就是struct semid_ds的指針,第二個參數會被忽略struct semid_ds buf;semctl(semid,0,IPC_STAT,&buf);//將頭部信息弄到buf里面去buf里面改一些什么東西了,然后想將buf設置回去semctl(semid,0,IPC_SET,&buf);cmd == IPC_INFOstruct seminfo __buf;semctl(semid,0,IPC_INFO,&__buf);.......由于第四個參數比較多變,為了統一這個參數,可以按照如下共同體建立一個結構體什么時候用哪一個就行union semun {int              val;    /* Value for SETVAL */struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */unsigned short  *array;  /* Array for GETALL, SETALL */struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */};cmd == SETALL,你怎么用這個共同體給我解決union semun hehe;hehe.array = malloc(sizeof(unsigned short) * nsems);//nsems就是信號量的個數//將值賦值到這個數組里面去hehe.array[0] = 3;hehe.array[1] = 1;....hehe.array[nsems - 1] = n;semctl(semid,2,SETALL,hehe.array);SEMOP(2)                   Linux Programmer's Manual                  SEMOP(2)NAMEsemop, semtimedop - System V semaphore operationsSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>struct sembuf arr[3];......int semop(int semid, struct sembuf *sops, size_t nsops);semid:你要操作哪一個信號集sops:操作的信息  有下面的結構struct sembuf{unsigned short sem_num;  /* 你要操作信號量集里面的那一個信號量 */short          sem_op;   /* 信號量的操作 P/V */P就是讓信號量的值遞減V就是讓信號量的值遞增所以這里填負數就是 P   -3 -> 將信號量的值 -= 3所以這里填正數就是 V   +3 -> 將信號量的值 += 3short          sem_flg;  /* 操作標志 */0 -> 阻塞IPC_NOWAIT -> 非阻塞SEM_UNDO  撤銷這個標志很有意義,當有這個標志之后內核就會關注這個進程如果進程沒有解鎖就退出了,內核就會將這個進程操作的信號量的值恢復到P之前 -- 防止帶鎖退出而出現的死鎖問題};nsops:sops這個玩意兒是一個數組的首地址,因此我需要將數組的元素個數傳進去可能操作多個信號量int semtimedop(int semid, struct sembuf *sops, size_t nsops,const struct timespec *timeout);//這個函數多了一個timeout的操作//表示限時等待semop這個函數如果是阻塞上鎖,別人沒有釋放鎖的時候,它是上不上去的,這個時候就會卡在semopsemtimedop給了一個時間,這個時間到了就不等了struct timespec {__kernel_time_t tv_sec;          /* 秒 */long       tv_nsec;      /* 納秒 */};//假設你要等 1s 500000ns的時間struct timespec tp;clock_gettime(CLOCK_REALTIME,&tp);//獲取現在的時間//往后等1s 500000ns的時間tp.tv_sec += 1;tp.tv_nsec += 500000;if(tp.tv_nsec > 1000000000)//進1了{tp.tv_sec++;tp.tv_nsec -= 1000000000;}semtimedop(,,,&tp);返回值:成功0,失敗-1,同時errno被設置死鎖問題:只能避免死鎖,如果出現死鎖你是你的代碼有問題,我們需要需要解決這個bug如果有一個變量i = 1;進程1對這個i++;進程2對這個i--兩個進程不知道什么時候會運行,請問,當兩個進程都運行完一遍之后這個i的值為多少進程1對i的操作可以分為三步:1讀取i的值放在自己的內存空間 2對內存進行++ 3將結果寫入到i的內存空間(這三步是原子操作)進程2對i的操作可以分為三步:4讀取i的值放在自己的內存空間 5對內存進行-- 6將結果寫入到i的內存空間(這三步是原子操作)145623 -> 2123456 -> 1456123 -> 1412356 -> 0451236 -> 0POSIX semaphore -> 單個信號量有名信號量:內容在內核里面,在文件系統里面有一個名字因此可以用于不同的進程間或者線程間無名信號量:沒有名字,因此只能通過遺傳,因此只能用于有親緣關系的進程間如果這個無名信號量存在于父進程的內存空間,當子進程拷貝過去之后,父子里面的信號量就變成兩個了這個時候父進程就會操作父進程,子進程操作的就是子進程的,這樣就起不到保護的作用了那么我們就需要讓這個信號存在于共享內存里面 --- 這種操作明顯很麻煩,不建議使用或者線程間有名信號量:需要創建或者打開
NAMEsem_open - initialize and open a named semaphoreSYNOPSIS#include <fcntl.h>           /* For O_* constants */#include <sys/stat.h>        /* For mode constants */#include <semaphore.h>sem_t *sem_open(const char *name, int oflag);//純粹的打開一個信號量sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);//這個玩意可以打開或者創建一個信號量name:一個存在的路徑名  這個路徑名里面只能有一個 /,開頭也是它"/hehe.sem"oflag:標志0 打開O_CREAT 創建標記mode:你創建的時候需要這個權限  0664value:創建的時候才會有值的設置,如果是打開一個信號量是沒有值的設置的只有創建成功才會被設置進去返回值:成功返回一個sem_t指針,指向我們的信號量失敗返回SEM_FAILED,同時errno被設置Link with -pthread.//鏈接這個庫 pthread  因此編譯的時候需要在后面加上 -lpthread無名信號量只能初始化
NAMEsem_init - initialize an unnamed semaphoreSYNOPSIS#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);sem:保存我們的信號量pshared:共享方式0 :進程的內部線程共享1 : 不同進程間的共享 ---- 這種不建議使用value:值成功0 失敗-1Link with -pthread.P操作
NAMEsem_wait, sem_timedwait, sem_trywait - lock a semaphore 上鎖SYNOPSIS#include <semaphore.h>int sem_wait(sem_t *sem);//等待版本 P操作int sem_trywait(sem_t *sem);//嘗試版本  非阻塞 P操作int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);//限時等待版本 P操作sem:你要對哪個信號量進程P操作Link with -pthread.V操作
NAMEsem_post - unlock a semaphore  解鎖SYNOPSIS#include <semaphore.h>int sem_post(sem_t *sem);sem:你要對哪個信號量進程P操作Link with -pthread.POSIX信號量的其它操作NAMEsem_getvalue - get the value of a semaphore獲取信號量的值
SYNOPSIS#include <semaphore.h>int sem_getvalue(sem_t *sem, int *sval);sem:你要對哪個信號量進程進行操作sval:值寫入到這個內存空間Link with -pthread.NAMEsem_close - close a named semaphore//關閉不是刪除關閉有名信號量
SYNOPSIS#include <semaphore.h>int sem_close(sem_t *sem);sem:你要對哪個信號量進程進行操作Link with -pthread.NAMEsem_unlink - remove a named semaphore//刪除一個有名信號量SYNOPSIS#include <semaphore.h>int sem_unlink(const char *name);name:路徑名Link with -pthread.NAMEsem_destroy - destroy an unnamed semaphore銷毀一個無名信號量
SYNOPSIS#include <semaphore.h>int sem_destroy(sem_t *sem);sem:你要銷毀哪個無名信號量Link with -pthread.正式項目里面一旦發現是多個進程/線程對一個資源進行讀寫,那么我們就要保護

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

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

相關文章

Scikit-learn通關秘籍:從鳶尾花分類到房價預測

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;H卡級別算力&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生專屬優惠。 決策樹/SVM/KNN算法對比 模型評估指標解析 讀者收獲&#xff1a;掌握經典機器學習全流程 …

rsync + inotify 數據實時同步

rsync inotify 數據實時同步 一、rsync簡介 rsync是linux系統下的數據鏡像備份工具。使用快速增量備份工具Remote Sync可以遠程同步&#xff0c; 支持本地復制&#xff0c;或者與其他SSH、rsync主機同步 二、rsync三種命令 Rsync的命令格式常用的有以下三種&#xff1a;&#…

Linux基礎介紹-3——第一階段

文章目錄一、進程管理1.1 進程的基本概念1.2 常見管理命令1.3 進程優先級調整&#xff1a;nice 與 renice二、軟件包管理三、防火墻管理四、shell腳本五、xshell鏈接kali一、進程管理 1.1 進程的基本概念 進程是程序的動態執行實例&#xff0c;每個進程都有唯一的 PID&#x…

python 可迭代對象相關知識點

1. 什么是可迭代對象 (Iterable) 在 Python 里&#xff0c;可迭代對象指的是&#xff1a; &#x1f449; 能夠一次返回一個元素的對象&#xff0c;可以被 for 循環遍歷。 常見的可迭代對象有&#xff1a; 序列類型&#xff1a;list、tuple、str集合類型&#xff1a;set、dict&a…

ijkplayer Android 編譯

一、下載編譯庫文件1.1 編譯庫文件環境&#xff1a;ubuntu 20.04 版本liangtao:ffmpeg$lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal1.2 項目源碼下載使用 git 下載 ijkplayer&#…

snn前向推理時間計算(處理器實現)

公式 Tinf(1?sparsity)number of synapsesnumber of sub-processorsSIMD ways T_{\text{inf}} \frac{(1-\text{sparsity})\times \text{number of synapses}} {\text{number of sub-processors}\times \text{SIMD ways}} Tinf?number of sub-processorsSIMD ways(1?sparsity…

Linux------《操作系統全景速覽:Windows·macOS·Linux·Unix 對比及 Linux 發行版實戰指南》

&#xff08;一&#xff09;常見操作系統&#xff08;system&#xff09;電腦&#xff1a;Windows,Macos,Linux,UnixWindows&#xff1a;微軟公司開發的一款桌面操作系統&#xff08;閉源系統&#xff09;。版本有dos&#xff0c;win98&#xff0c;win NT&#xff0c;win XP , …

Three.js 初級教程大全

本文檔旨在為初學者提供一個全面的 Three.js 入門指南。我們將從 Three.js 的基本概念開始&#xff0c;逐步介紹如何創建場景、添加物體、設置材質、使用光照和相機&#xff0c;以及如何實現簡單的動畫和交互。通過本教程&#xff0c;你將能夠掌握 Three.js 的核心知識&#xf…

遙感領域解決方案丨高光譜、無人機多光譜、空天地數據識別與計算

一&#xff1a;AI智慧高光譜遙感實戰&#xff1a;手撕99個案例項目、全覆蓋技術鏈與應用場景一站式提升方案在遙感技術飛速發展的今天&#xff0c;高光譜數據以其獨特的光譜分辨率成為環境監測、精準農業、地質勘探等領域的核心數據源。然而&#xff0c;海量的波段數據、復雜的…

(LeetCode 面試經典 150 題) 114. 二叉樹展開為鏈表 (深度優先搜索dfs+鏈表)

題目&#xff1a;114. 二叉樹展開為鏈表 思路&#xff1a;深度優先搜索dfs鏈表&#xff0c;時間復雜度0(n)。 C版本&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : …

《線程狀態轉換深度解析:從阻塞到就緒的底層原理》

目錄 一、線程的五種基本狀態 二、線程從 RUNNABLE 進入阻塞 / 等待狀態的三種典型場景 1. 調用sleep(long millis)&#xff1a;進入 TIMED_WAITING 狀態 2. 調用wait()&#xff1a;進入 WAITING/TIMED_WAITING 狀態 3. 等待 I/O 資源或獲取鎖失敗&#xff1a;進入 BLOCKE…

面經整理-猿輔導-內容服務后端-java實習

部門管理系統設計 題目要求 設計部門 MySQL 數據表實現接口&#xff1a;根據中間部門 ID 獲取其下屬葉子部門 ID設計包含子節點列表的 Java 數據對象&#xff0c;并實現批量獲取功能 一、MySQL 部門表設計 表結構 CREATE TABLE department (id BIGINT PRIMARY KEY AUTO_INCREME…

Openharmony之window_manager子系統源碼、需求定制詳解

1. 模塊概述 Window Manager 模塊是 OpenHarmony 操作系統的核心窗口管理系統,負責窗口的創建、銷毀、布局、焦點管理、動畫效果以及與硬件顯示的交互。該模塊采用客戶端-服務端架構,提供完整的窗口生命周期管理和用戶界面交互支持。 1.1架構總覽 Window Manager Client 應…

《CDN加速的安全隱患與解決辦法:如何構建更安全的網絡加速體系》

CDN&#xff08;內容分發網絡&#xff09;作為提升網站訪問速度的關鍵技術&#xff0c;被廣泛應用于各類互聯網服務中。然而&#xff0c;在享受加速優勢的同時&#xff0c;CDN也面臨諸多安全隱患。本文將解析常見的CDN安全問題&#xff0c;并提供實用的解決辦法&#xff0c;幫助…

【Linux指南】GCC/G++編譯器:庖丁解牛——從源碼到可執行文件的奇幻之旅

不只是簡單的 gcc hello.c 每一位Linux C/C++開發者敲下的第一行編譯命令,幾乎都是 gcc hello.c -o hello 或 g++ hello.cpp -o hello。這像一句神奇的咒語,將人類可讀的源代碼變成了機器可執行的二進制文件。但在這條簡單的命令背后,隱藏著一個如同精密鐘表般復雜的多步流…

地區電影市場分析:用Python爬蟲抓取貓眼_燈塔專業版各地區票房

在當今高度數據驅動的影視行業&#xff0c;精準把握地區票房表現是制片方、宣發團隊和影院經理做出關鍵決策的基礎。一部電影在北上廣深的表現與二三線城市有何差異&#xff1f;哪種類型的電影在特定區域更受歡迎&#xff1f;回答這些問題&#xff0c;不能再依賴“拍腦袋”和經…

Spark03-RDD02-常用的Action算子

一、常用的Action算子 1-1、countByKey算子 作用&#xff1a;統計key出現的次數&#xff0c;一般適用于K-V型的RDD。 【注意】&#xff1a; 1、collect()是RDD的算子&#xff0c;此時的Action算子&#xff0c;沒有生成新的RDD&#xff0c;所以&#xff0c;沒有collect()&…

[Android] 顯示的內容被導航欄這擋住

上圖中彈出的對話框的按鈕“Cancel/Save”被導航欄遮擋了部分顯示&#xff0c;影響了使用。Root cause: Android 應用的主題是 Theme.AppCompat.Light1. 修改 AndroidManifest.xml 將 application 標簽的 android:theme 屬性指向新的自定義主題&#xff1a;<applicationandr…

分貝單位全指南:從 dB 到 dBm、dBc

引言在射頻、音頻和通信工程中&#xff0c;我們經常會在示波器、頻譜儀或測試報告里看到各種各樣的dB單位&#xff0c;比如 dBm、dBc、dBV、dBFS 等。它們看起來都帶個 dB&#xff0c;實則各有不同的定義和參考基準&#xff1a;有的表示相對功率&#xff0c;有的表示電壓電平&a…

怎么確定mysql 鏈接成功了呢?

asyncio.run(test_connection()) ? Connection failed: cryptography package is required for sha256_password or caching_sha2_password auth methods 根據你提供的錯誤信息,問題出現在 MySQL 的認證插件和加密連接配置上。以下是幾種解決方法: 1. 安裝 cryptography 包…