[Linux]共享內存

共享內存是UNIX提供的進程間通信手段中速度最快的一種,也是最快的IPC形式。為什么是最快的呢,因為數據不需要在客戶進程和服務器進程之間復制,所以是最快的一種IPC。這是虛存中由多個進程共享的一個公共內存塊。

兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。

如果服務器進程正在將數據放入到共享存儲區,則在它做完這一操作之前,客戶進程不應當去取這些數據。通常信號量用于同步共享存儲訪問。

由于共享內存是通過映射到同一塊物理內存后進行的通信,因此肯定需要映射到內存的函數和解除映射的函數,主要有以下幾種

#define SHMAT       21//空間映射:把上面打開的內存區域連接到用戶的進程空間中  
#define SHMDT       22//解除映射:將共享內存從當前進程中分離  
#define SHMGET      23//創建打開一個內存區域  
#define SHMCTL      24//內存區域的控制:包括初始化和刪除內存區域。

注意:共享內存通信本身沒有提供同步機制,如果同時被多個進程進行映射和寫操作,會導致破壞該內存空間的內容。因此在實際應用過程中,需要通過其他的機制來同步對共享內存的訪問。比如信號量。

內核為每個共享存儲段維護著一個結構,該結構至少要為每個共享存儲段包含以下成員:

struct shmid_ds 
{struct ipc_perm shm_perm; //ipc結構體size_t shm_segsz;  //請求的sizepid_t shm_lpid;   //0pid_t shm_cpid;   //創建者pidshmatt_t shm_nattch; //當前掛載數time_t shm_atime;  //0time_t shm_dtime; //0time_t shm_ctime;  //設置為當前時間
};

1.調用的第一個函數為shmget:

#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
//key是創建共享內存id的唯一標識符,size為共享存儲段的長度,以字節為單位,通常將其向上取為系統頁長的整數倍。如果不是整頁,則最后剩余部分是不可用的。flag表示相應的權限位。

2.shmctl函數對共享內存段執行多種操作

#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
//IPC_RMID:從系統中刪除該共享存儲段。

3.一旦創建了共享存儲段,進程就可調用shmat將其連接到它的地址空間中。

void *shmat(int shmid,const void* addr,int flag);
//返回若成功,返回指向共享存儲段的指針,出錯返回-1
//如果成功執行,那么內核將使與該共享存儲段相關的shmid_ds結構中的shm_nattch計數器值加1;當對共享存儲段的操作已經結束時,則調用shmat與該段分離。這里并沒有從系統中刪除相關的數據結構,該標識符和ipc數據結構仍然存在。
int shmdt(const void* addr);  //為掛載時的addr
//如果調用成功,則使與該共享存儲段相關的shmid_ds結構中的shm_nattch計數器值減1

具體代碼實現:

//comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>#define PATHNAME "."
#define PROJ_ID 0X6667int CreateShm(int size);
int GetShm(int size);int destroyShm(int shmid);#endif   //_COMM_H_
//comm.c
#include"comm.h"int CommShm(int size,int flags)
{key_t key = ftok(PATHNAME,PROJ_ID);if(key < 0){perror("ftok");return -1;}int shmid = shmget(key,size,flags); if(shmid < 0){perror("shmget");return -2;}return shmid;
}int CreateShm(int size)
{return CommShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int GetShm(int size)
{return CommShm(size,IPC_CREAT);
}
int destroyShm(int shmid)
{if(shmctl(shmid,IPC_RMID,NULL) < 0){perror("shmctl");return -1;}return 0;
}
//server.c
#include"comm.h"int main()
{int shmid = CreateShm(4096);
//  printf("hello server!\n");char *addr = shmat(shmid,NULL,0);if(addr == NULL){return 1;}int i = 0;char s = 'a';while(1){addr[i] = s;s++;}addr[i] = 0;sleep(4);shmdt(addr);printf("shm quit!\n");return 0;
}
//client.c
#include"comm.h"int main()
{int shmid = GetShm(4096);//printf("hello client!\n");char *addr = shmat(shmid,NULL,0);if(addr == NULL)return 2;printf("%s",addr);sleep(10);shmdt(addr);    printf("shm quit!\n");return 0;
}

運行結果:

這里寫圖片描述

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

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

相關文章

僵尸進程的產生,危害和解決方案

概念 僵死狀態&#xff08;Zombies&#xff09;是一個比較特殊的狀態。 當進程退出并且父進程沒有讀取到子進程退出的返回代碼時就會產生僵尸進程。僵尸進程會以終止狀態保持在進程表中&#xff0c;并且會一直在等待父進程讀取退出狀態代碼。所以&#xff0c;只要子進程退出&…

CString string 轉換

https://www.cnblogs.com/HappyEDay/p/7016162.html

[Linux]gdb調試多進程多線程例程

gdb相信學linux的同學已經比較熟悉了吧&#xff0c;它是linux下代碼調試工具。我們在寫c語言&#xff0c;c的代碼時經常會用到&#xff0c;它有一些常用的調試命令: run&#xff08;r&#xff09;&#xff1a;運行程序&#xff0c;如果有斷點在下一個斷點處停止 start&#xf…

gdb調試常用命令速查(段錯誤調試)

編譯程序時需要加上-g&#xff0c;之后才能用gdb進行調試&#xff1a;gcc -g main.c -o main gdb中命令&#xff1a; 回車鍵&#xff1a;重復上一命令 &#xff08;gdb&#xff09;help&#xff1a;查看命令幫助&#xff0c;具體命令查詢在gdb中輸入help 命令,簡寫h &…

C語言字符串 小記

#include "stdafx.h" #include <iostream> #include <string.h> using namespace std;int _tmain(int argc, _TCHAR* argv[]) {char str1[] "12345"; // ""括起來的字符串 會在末尾增加 \0 cout << sizeof(str1) << en…

[Linux]守護進程(精靈進程)

一、守護進程是什么 守護進程是生存期很長的一種進程&#xff0c;可以說它是7*24小時工作的。&#xff08;什么是7*24&#xff0c;一周7天&#xff0c;每天24小時&#xff0c;這不就是一年365天一直在工作嘛&#xff0c;還搞的這么詼諧&#xff0c;哈哈&#xff09;。它們常常…

linux命令行界面下ctrl 常用組合鍵速查表

Ctrlz 暫停正在運行的程序 Ctrll 清屏 Ctrld 結束輸入或退出shell Ctrla 切換到命令行開始 Ctrle 切換到命令行末尾 Ctrlu 刪除光標前內容 Ctrlk 刪除光標后內容 Ctrlxu 撤銷操作

[Linux]運輸層的端口

既然提到端口&#xff0c;我們就來分析一下為什么要使用端口的緣由吧。我們首先要知道的是&#xff0c;運輸層有復用和分用的功能。應用層所有的應用進程都可以通過運輸層再傳送到IP層&#xff0c;這就是復用。運輸層從IP層收到數據后必須交付到指明的應用進程&#xff0c;這就…

淺談shell中的clear命令實現

NAME(名稱) clear - 清除終端屏幕 SYNOPSIS(總覽) clear DESCRIPTION(描述) clear可以在允許的情況下清屏. 它會在環境變量中查找終端的類型, 然后到terminfo數據庫中找出清屏的方法. 《man手冊》 #include <stdio.h>int clear_main(int argc, char **argv) {/* Th…

C++ 對引用的理解

引用可以看做是數據的一個別名&#xff0c;通過這個別名和原來的名字都能夠找到這份數據引用必須在定義的同時初始化&#xff0c;并且以后也要從一而終&#xff0c;不能再引用其它數據&#xff0c;這有點類似于常量&#xff08;const 變量&#xff09;。引用變量 里面 實際存儲…

[Linux]ARP協議

概念&#xff1a; 1. ARP協議(地址解析協議):由IP地址轉換為MAC地址的協議。IP地址&#xff1a;網絡號主機號。MAC地址&#xff1a;數據鏈路層的物理地址&#xff08;硬件地址&#xff09;。IP協議使用了ARP協議&#xff0c;因此被劃歸為網絡層&#xff0c;但其用途是從網絡層…

Makefile使用及多文件gdb 調試

文件內容 [koulocalhost makefile]$ cat 1.c #include "3.h" int main() {key_t key ftok(".",1);printf("%d\n",add(1,2));return 0; }[koulocalhost makefile]$ cat 2.c #include "3.h" int add(int a, int b) {return a b; } [k…

C++ 對引用的理解2

1.指針就是數據或代碼在內存中的地址&#xff0c;指針變量指向的就是內存中的數據或代碼。這里有一個關鍵詞需要強調&#xff0c;就是內存&#xff0c;指針只能指向內存&#xff0c;不能指向寄存器或者硬盤&#xff0c;因為寄存器和硬盤沒法尋址。 2.其實 C 代碼中的大部分內容…

Ubuntu各版本主要差異

Ubuntu各版本主要差異 (重定向自Ubuntu &#xff0c; kubuntu與xubuntu的差別 ) Ubuntu官方考慮到使用者的不同需求&#xff0c;提供各種不同的發行版。這幾種發行版本的差別在于桌面環境和預設安裝的軟體不同&#xff0c;但套件庫是采用一樣的&#xff0c;所以您當然可以在安…

[Linux]CRC校驗

CRC(Cyclic Redundancy Check),循環冗余校驗碼&#xff0c;是數據通信領域中最常用的一種差錯校驗碼&#xff0c;其特征是信息字段和校驗字段的長度可以任意選定。 CRC校驗步驟&#xff1a; CRC分為兩部分&#xff0c;前部分為信息碼&#xff0c;后部分為校驗碼&#xff1b;設…

visual studio 2015 配置好qt5后, 第一次運行出現 無法打開源文件“QtWidgets/QApplication”和無法運行rc.exe的解決方案

無法打開源文件“QtWidgets/QApplication” a.在工程中右擊項目&#xff0c;點擊屬性。 b.選擇VC目錄->包含目錄 c.選擇Qt安裝目錄中的頭文件包含目錄&#xff0c;一般為Qt版本號/版本號/編譯器名/include 比如&#xff1a;E:\Qt\Qt5.6.3\5.6.3\msvc2015\include 在C\C>附…

怎么在vs中查看一個數組的所有元素

在監視窗口&#xff0c;我們想要查看所有的數組元素。 這個時候 int arr[] {1,2,3} arr只顯示1 正確的方法 arr&#xff0c;10

[Linux]NAT和代理服務器

1. NAT&#xff1a;&#xff08;Network Address Translation&#xff09;是網絡地址轉換。 我們有這樣一種場景&#xff0c;在專用網內部的一些主機本來已經分配到了本地IP地址&#xff0c;但現在又想和因特網上的主機通信&#xff0c;我們可以設法再申請一些全球IP地址&…

使用 C++的第三方庫 jsoncpp的步驟以及出現的問題

Jsoncpp 是一個json解析庫 下載地址為&#xff1a; http://sourceforge.net/projects/jsoncpp/ 方法一&#xff1a;使用Jsoncpp生成的lib文件 解壓上面下載的Jsoncpp文件&#xff0c;在jsoncpp-src-0.5.0/makefiles/vs71目錄里找到jsoncpp.sln&#xff0c;用VS2008版本編譯&am…

常用的友元重載運算符OSTREAM

對<<運算符重載&#xff0c;讓他能和cout一起顯示對象內容。 顯示值可以使用show()&#xff0c;但是使用cout<<更方便。 ostream類對該運算符進行了重載&#xff0c;將其轉換成輸出工具。 cout就是一個ostream的對象&#xff0c;他可以自動識別所有的c基本類型。…