當前位置:首頁 » 電腦資訊 » 共享內存為什麼創建文件

共享內存為什麼創建文件

發布時間: 2022-05-10 07:12:20

1. windows 共享內存有幾種方式

  1. 使用shared類型的section,可以讓變數在同一個可執行文件(image)創建的多個進程間共享;

  2. 使用動態鏈接庫(DLL),可以讓變數在不同image創建的進程間共享

  3. 使用FileMapping,可以在不同進程間共享一段內存

2. 怎麼利用設計模式來更有效的使用共享內存

IOCTL 方法:應用程序分配共享內存

在用戶模式與核心模式之間共享內存的最簡單有效的方法是使用 IOCTL。IOCTL 有四種不同的類型,下列三種 IOCTL 使您可以在設備驅動程序中直接訪問用戶緩沖區:

METHOD_IN_DIRECT
METHOD_OUT_DIRECT
METHOD_NEITHER
在以上這些方法中沒有創建中間系統緩沖區。

METHOD_IN_DIRECT 和 METHOD_OUT_DIRECT 自動在 DeviceIoControl 中鎖定用戶指定的緩沖區,並為驅動程序創建內存描述列表 (MDL)。驅動程序可以從 MDL 得到一個系統地址,並根據 IOCTL 傳輸類型將信息傳入傳出緩沖區。由於所有的緩沖區驗證、鎖定及 MDL 創建均是通過 I/O 管理器來完成的,所以這是一種簡單的方法。

相反,METHOD_NEITHER 直接將用戶緩沖區提供給驅動程序,驅動程序必須適當地驗證緩沖區並鎖定緩沖區,如果需要,還要為緩沖區獲取一個系統地址。雖然這是通過設備驅動程序 I/O 子系統的最快捷路徑,但使用這種方法時也有一些應當注意的問題。有關其它信息,請參見 Microsoft Knowledge Base 中的下列文章:

Q126416 INFO:使用 METHOD_NEITHER IOCTL 的警告
要了解這三種不同的 IOCTL 如何工作,請參見以下 Microsoft Knowledge Base 文章:

Q178317 文件:IOCTL.exe:如何使用不同類型的 IOCTL
MmMapLockedPages 方法:設備驅動程序分配共享內存

在這種方法中,驅動程序通過 MmAllocateContiguousMemory 或 ExAllocatePoolXxx 函數分配內存,創建並建立描述緩沖區的 MDL,並使用 MmMapLockedPages 把內存映射到用戶進程地址空間中。用戶應用程序可以使用由 MmMapLockPages 返回的虛擬地址直接訪問系統內存。

由於應當在訪問內存的進程上下文中完成映射,所以此方法只能用於單層結構的驅動程序,這時可以保證 dispatch 常式在調用進程上下文中運行。您可以在任意數量的用戶過程地址空間上映射同一個系統緩沖區。不過,應當設計一種保護機制,使驅動程序及所有應用程序對內存的訪問同步。進一步說,應當在終止進程之前或者一旦使用完緩沖區就在映射緩沖區的相同進程上下文中取消緩沖區的映射。下面介紹將驅動程序緩沖區映射至某個用戶進程時需採取的步驟:

首先如下分配內存:

SystemVirtualAddress = MmAllocateContiguousMemory(NumberOfBytes,
HighestAcceptableAddress); 或
SystemVirtualAddress = ExAllocatePool(PoolType, NumberOfBytes);

如下分配一個 MDL:

Mdl = IoAllocateMdl(SystemVirtualAddress, NumberOfBytes, FALSE,
FALSE, NULL);

建立 MDL 以描述內存頁。如果已經分配了非頁面緩沖池中的內存,請使用:

MmBuildMdlForNonPagedPool(Mdl);
如果分配了頁面緩沖池中的內存,請使用:

MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
如下將鎖定的頁面映射至進程的用戶地址空間中:

UserVirtualAddress = MmMapLockedPages(Mdl, UserMode);

前三步可以在 DriverEntry 或 Dispatch 常式中完成。但是,將緩沖區映射至用戶地址空間的最後一步,應當在運行於調用進程上下文的某個常式(通常是單層驅動程序的 dispatch 常式)中完成。

您可以在某個提高的 IRQL 級及任何進程上下文(即中斷服務常式 (ISR) 及延遲過程調用 (DPC))的驅動程序中使用 SystemVirtualAddress,在應用程序或運行正確進程上下文的驅動程序中使用 UserVirtualAddress。

按照下列步驟取消映射並釋放緩沖區:
首先從用戶地址空間中取消頁面映射。應在映射 UserVirtualAddress 的進程上下文中運行時調用函數:
MmUnmapLockedPages(UserVirtualAddress, Mdl);
如果使用 MmProbleAndLockPages 鎖定了頁面,則使用以下函數解鎖:
MmUnlockPages(Mdl)
釋放 MDL:
IoFreeMdl(Mdl);
釋放系統內存:
MmFreeContiguousMemory(SystemVirtualAddress); 或
ExFreePool(SystemVirtualAddress);
共享內存對象方法

使用保存在頁面文件上的內存映射文件是用於在用戶進程之間共享內存的常用方法。不過,您可以使用以上技術在用戶過程及設備驅動程序之間共享內存。使用這種技術有兩種方法。在第一種方法中,驅動程序可以創建命名內存對象(稱為 section 對象),一個或多個應用程序通過使用 OpenFileMapping 打開以上對象,然後調用 MapViewOfFile 函數來得到指向它的指針。通過指定以上對象的保護屬性,可以定義某個進程使用內存的方式。

在第二種方法中,應用程序可以使用 CreateFileMapping 在用戶模式下創建一個命名內存對象。驅動程序通過使用 ZwMapViewOfSection 函數及調用 ZwMapViewOfSection 得到其指針來打開以上內存對象。您應當使用異常處理程序在核心模式中訪問該內存地址。有關使用這種技術的範例,請參見下列 Microsoft Knowledge Base 文章:

Q194945 樣例:有關在核心和用戶模式之間共享內存的 Section.exe
因為總是在進程的用戶地址空間(小於 0x80000000,不管是在核心模式還是在用戶模式中創建對象)上映射對象,所以只在進程上下文中訪問地址時地址才有效。在相同內存對象上對 MapViewOfFile 或 ZwMapViewOfSection 的每次調用將返回一個不同的內存地址,即使對於相同的進程也是如此。通常不建議使用這種方法,特別是對於低級設備驅動程序而言。如前所述,這是因為地址范圍被限制於映射對象的進程中,不能在 DPC 或 ISR 中訪問。而且,在核心模式中創建內存對象的 API 沒有記載於 DDK 中。

然而,要在提高的 IRQL (如 DPC 或 ISR)上使用該地址,您一定要查明並鎖定緩沖區頁面,並得到如 IOCTL 方法中所述的系統虛擬地址 (MmGetSystemAddressForMdl)。

只有準備在兩個(或多個)用戶進程和一個(或多個)設備驅動程序之間共享內存時,這種方法才比較簡單容易。否則,使用 IOCTL 技術在一個用戶過程及一個設備驅動程序之間共享內存將更為簡單有效。

3. 關於IPC$

程間通信就是在不同進程之間傳播或交換信息,那麼不同進程之間存在著什麼雙方都可以訪問的介質呢?進程的用戶空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享內存區。但是,系統空間卻是「公共場所」,所以內核顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪問的外設了。在這個意義上,兩個進程當然也可以通過磁碟上的普通文件交換信息,或者通過「注冊表」或其它資料庫中的某些表項和記錄交換信息。廣義上這也是進程間通信的手段,但是一般都不把這算作「進程間通信」。因為那些通信手段的效率太低了,而人們對進程間通信的要求是要有一定的實時性。
進程間通信主要包括管道, 系統IPC(包括消息隊列,信號量,共享存儲), SOCKET.
管道包括三種:1)普通管道PIPE, 通常有種限制,一是半雙工,只能單向傳輸;二是只能在父子進程間使用. 2)流管道s_pipe: 去除了第一種限制,可以雙向傳輸. 3)命名管道:name_pipe, 去除了第二種限制,可以在許多並不相關的進程之間進行通訊.
系統IPC的三種方式類同,都是使用了內核里的標識符來識別.
FAQ1: 管道與文件描述符,文件指針的關系?
答: 其實管道的使用方法與文件類似,都能使用read,write,open等普通IO函數. 管道描述符來類似於文件描述符. 事實上, 管道使用的描述符, 文件指針和文件描述符最終都會轉化成系統中SOCKET描述符. 都受到系統內核中SOCKET描述符的限制. 本質上LINUX內核源碼中管道是通過空文件來實現.
FAQ2: 管道的使用方法?
答: 主要有下面幾種方法: 1)pipe, 創建一個管道,返回2個管道描述符.通常用於父子進程之間通訊. 2)popen, pclose: 這種方式只返回一個管道描述符,常用於通信另一方是stdin or stdout; 3)mkpipe: 命名管道, 在許多進程之間進行交互.
FAQ3: 管道與系統IPC之間的優劣比較?
答: 管道: 優點是所有的UNIX實現都支持, 並且在最後一個訪問管道的進程終止後,管道就被完全刪除;缺陷是管道只允許單向傳輸或者用於父子進程之間.
系統IPC: 優點是功能強大,能在毫不相關進程之間進行通訊; 缺陷是關鍵字KEY_T使用了內核標識,佔用了內核資源,而且只能被顯式刪除,而且不能使用SOCKET的一些機制,例如select,epoll等.
FAQ4: WINDOS進程間通信與LINUX進程間通信的關系?
答: 事實上,WINDOS的進程通信大部分移植於UNIX, WINDOS的剪貼板,文件映射等都可從UNIX進程通信的共享存儲中找到影子.
FAQ5: 進程間通信與線程間通信之間的關系?
答: 因為WINDOWS運行的實體是線程, 狹義上的進程間通信其實是指分屬於不同進程的線程之間的通訊.而單個進程之間的線程同步問題可歸並為一種特殊的進程通信.它要用到內核支持的系統調用來保持線程之間同步. 通常用到的一些線程同步方法包括:Event, Mutex, 信號量Semaphore, 臨界區資源等.
Linux的進程間通信(IPC,InterProcess Communication)通信方法有管道、消息隊列、信號量、共享內存、套介面等。
管道分為有名管道和無名管道,無名管道只能用於親屬進程之間的通信,而有名管道則可用於無親屬關系的進程之間。
#define INPUT 0
#define OUTPUT 1
void main()
{
int file_descriptors[2];
/*定義子進程號 */
pid_t pid;
char buf[BUFFER_LEN];
int returned_count;
/*創建無名管道*/
pipe(file_descriptors);
/*創建子進程*/
if ((pid = fork()) == - 1)
{
printf("Error in fork\n");
exit(1);
}
/*執行子進程*/
if (pid == 0)
{
printf("in the spawned (child) process...\n");
/*子進程向父進程寫數據,關閉管道的讀端*/
close(file_descriptors[INPUT]);
write(file_descriptors[OUTPUT], "test data", strlen("test data"));
exit(0);
}
else
{
/*執行父進程*/
printf("in the spawning (parent) process...\n");
/*父進程從管道讀取子進程寫的數據,關閉管道的寫端*/
close(file_descriptors[OUTPUT]);
returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));
printf("%d bytes of data received from spawned process: %s\n",
returned_count, buf);
}
}
上述程序中,無名管道以int pipe(int filedis[2]);方式定義,參數filedis返回兩個文件描述符filedes[0]為讀而打開,filedes[1]為寫而打開,filedes[1]的輸出是filedes[0]的輸入;
在Linux系統下,有名管道可由兩種方式創建(假設創建一個名為「fifoexample」的有名管道):
(1)mkfifo("fifoexample","rw");
(2)mknod fifoexample p
mkfifo是一個函數,mknod是一個系統調用,即我們可以在shell下輸出上述命令。
有名管道創建後,我們可以像讀寫文件一樣讀寫之:
/* 進程一:讀有名管道*/
void main()
{
FILE *in_file;
int count = 1;
char buf[BUFFER_LEN];
in_file = fopen("pipeexample", "r");
if (in_file == NULL)
{
printf("Error in fdopen.\n");
exit(1);
}
while ((count = fread(buf, 1, BUFFER_LEN, in_file)) > 0)
printf("received from pipe: %s\n", buf);
fclose(in_file);
}
/* 進程二:寫有名管道*/
void main()
{
FILE *out_file;
int count = 1;
char buf[BUFFER_LEN];
out_file = fopen("pipeexample", "w");
if (out_file == NULL)
{
printf("Error opening pipe.");
exit(1);
}
sprintf(buf, "this is test data for the named pipe example\n");
fwrite(buf, 1, BUFFER_LEN, out_file);
fclose(out_file);
}
消息隊列用於運行於同一台機器上的進程間通信,與管道相似;
共享內存通常由一個進程創建,其餘進程對這塊內存區進行讀寫。得到共享內存有兩種方式:映射/dev/mem設備和內存映像文件。前一種方式不給系統帶來額外的開銷,但在現實中並不常用,因為它控制存取的是實際的物理內存;常用的方式是通過shmXXX函數族來實現共享內存:
int shmget(key_t key, int size, int flag); /* 獲得一個共享存儲標識符 */
該函數使得系統分配size大小的內存用作共享內存;
void *shmat(int shmid, void *addr, int flag); /* 將共享內存連接到自身地址空間中*/
shmid為shmget函數返回的共享存儲標識符,addr和flag參數決定了以什麼方式來確定連接的地址,函數的返回值即是該進程數據段所連接的實際地址。此後,進程可以對此地址進行讀寫操作訪問共享內存。
本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取狀況。一般說來,為了獲得共享資源,進程需要執行下列操作:
(1)測試控制該資源的信號量;
(2)若此信號量的值為正,則允許進行使用該資源,進程將進號量減1;
(3)若此信號量為0,則該資源目前不可用,進程進入睡眠狀態,直至信號量值大於0,進程被喚醒,轉入步驟(1);
(4)當進程不再使用一個信號量控制的資源時,信號量值加1,如果此時有進程正在睡眠等待此信號量,則喚醒此進程。
下面是一個使用信號量的例子,該程序創建一個特定的IPC結構的關鍵字和一個信號量,建立此信號量的索引,修改索引指向的信號量的值,最後清除信號量:
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
void main()
{
key_t unique_key; /* 定義一個IPC關鍵字*/
int id;
struct sembuf lock_it;
union semun options;
int i;
unique_key = ftok(".", 'a'); /* 生成關鍵字,字元'a'是一個隨機種子*/
/* 創建一個新的信號量集合*/
id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);
printf("semaphore id=%d\n", id);
options.val = 1; /*設置變數值*/
semctl(id, 0, SETVAL, options); /*設置索引0的信號量*/
/*列印出信號量的值*/
i = semctl(id, 0, GETVAL, 0);
printf("value of semaphore at index 0 is %d\n", i);
/*下面重新設置信號量*/
lock_it.sem_num = 0; /*設置哪個信號量*/
lock_it.sem_op = - 1; /*定義操作*/
lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/
if (semop(id, &lock_it, 1) == - 1)
{
printf("can not lock semaphore.\n");
exit(1);
}
i = semctl(id, 0, GETVAL, 0);
printf("value of semaphore at index 0 is %d\n", i);
/*清除信號量*/
semctl(id, 0, IPC_RMID, 0);
}
套接字通信並不為Linux所專有,在所有提供了TCP/IP協議棧的操作系統中幾乎都提供了socket,而所有這樣操作系統,對套接字的編程方法幾乎是完全一樣的。
進程間通信各種方式效率比較
類型
無連接
可靠
流控制
記錄
消息類型優先順序

4. 進程間通信 內存映射和共享內存的區別

內存映射文件是利用虛擬內存把文件映射到進程的地址空間中去,在此之後進程操作文件,就像操作進程空間里的地址一樣了,比如使用c語言的memcpy等內存操作的函數。這種方法能夠很好的應用在需要頻繁處理一個文件或者是一個大文件的場合,這種方式處理IO效率比普通IO效率要高
共享內存是內存映射文件的一種特殊情況,內存映射的是一塊內存,而非磁碟上的文件。共享內存的主語是進程(Process),操作系統默認會給每一個進程分配一個內存空間,每一個進程只允許訪問操作系統分配給它的哪一段內存,而不能訪問其他進程的。而有時候需要在不同進程之間訪問同一段內存,怎麼辦呢?操作系統給出了創建訪問共享內存的API,需要共享內存的進程可以通過這一組定義好的API來訪問多個進程之間共有的內存,各個進程訪問這一段內存就像訪問一個硬碟上的文件一樣。而.Net 4.0中引入了System.IO. MemoryMappedFiles命名空間,這個命名空間的類對windows 共享內存相關API做了封裝,使.Net程序員可以更方便的使用內存映射文件。

5. 什麼是共享內存,就是有的筆記本是共享內存,多大啊共享內存好嗎和256M的哪個好

共享內存指在多處理器的計算機系統中,可以被不同中央處理器(CPU)訪問的大容量內存。由於多個CPU需要快速訪問存儲器,這樣就要對存儲器進行緩存(Cache)。任何一個緩存的數據被更新後,由於其他處理器也可能要存取,共享內存就需要立即更新,否則不同的處理器可能用到不同的數據。共享內存 (shared memory)是 Unix下的多進程之間的通信方法 ,這種方法通常用於一個程序的多進程間通信,實際上多個程序間也可以通過共享內存來傳遞信息。

共享內存的創建
共享內存是存在於內核級別的一種資源,在shell中可以使用ipcs命令來查看當前系統IPC中的狀態,在文件系統/proc目錄下有對其描述的相應文件。函數shmget可以創建或打開一塊共享內存區。函數原型如下: #include <sys/shm.h> int shmget( key_t key, size_t size, int flag ); 函數中參數key用來變換成一個標識符,而且每一個IPC對象與一個key相對應。當新建一個共享內存段時,size參數為要請求的內存長度(以位元組為單位)。 注意:內核是以頁為單位分配內存,當size參數的值不是系統內存頁長的整數倍時,系統會分配給進程最小的可以滿足size長的頁數,但是最後一頁的剩餘部分內存是不可用的。 當打開一個內存段時,參數size的值為0。參數flag中的相應許可權位初始化ipc_perm結構體中的mode域。同時參數flag是函數行為參數,它指定一些當函數遇到阻塞或其他情況時應做出的反應。shmid_ds結構初始化如表14-4所示。
編輯本段初始化
shmid_ds結構數據 初 值 shmid_ds結構數據 初 值
shm_lpid 0 shm_dtime 0
shm_nattach 0 shm_ctime 系統當前值
shm_atime 0 shm_segsz 參數 size
下面實例演示了使用shmget函數創建一塊共享內存。程序中在調用shmget函數時指定key參數值為IPC_PRIVATE,這個參數的意義是創建一個新的共享內存區,當創建成功後使用shell命令ipcs來顯示目前系統下共享內存的狀態。命令參數-m為只顯示共享內存的狀態。 (1)在vi編輯器中編輯該程序如下: 程序清單14-8 create_shm.c 使用shmget函數創建共享內存 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> #define BUFSZ 4096 int main ( void ) { int shm_id; /*共享內存標識符*/ shm_id=shmget(IPC_PRIVATE, BUFSZ, 0666 ) ; if (shm_id < 0 ) { /*創建共享內存*/ perror( "shmget" ) ; exit ( 1 ); } printf ( "successfully created segment : %d \n", shm_id ) ; system( "ipcs -m"); /*調用ipcs命令查看IPC*/ exit( 0 ); } (2)在shell中編譯該程序如下: $gcc create_shm.c–o create_shm (3)在shell中運行該程序如下: $./ create_shm successfully created segment : 2752516 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中使用shmget函數來創建一段共享內存,並在結束前調用了系統shell命令ipcs –m來查看當前系統IPC狀態。
編輯本段共享內存的操作
由於共享內存這一特殊的資源類型,使它不同於普通的文件,因此,系統需要為其提供專有的操作函數,而這無疑增加了程序員開發的難度(需要記憶額外的專有函數)。使用函數shmctl可以對共享內存段進行多種操作,其函數原型如下: #include <sys/shm.h> int shmctl( int shm_id, int cmd, struct shmid_ds *buf ); 函數中參數shm_id為所要操作的共享內存段的標識符,struct shmid_ds型指針參數buf的作用與參數cmd的值相關,參數cmd指明了所要進行的操作,其解釋如表14-5所示。
編輯本段cmd參數詳解
cmd的值 意 義
IPC_STAT 取shm_id所指向內存共享段的shmid_ds結構,對參數buf指向的結構賦值
IPC_SET 使用buf指向的結構對sh_mid段的相關結構賦值,只對以下幾個域有作用,shm_perm. uid shm_perm.gid以及shm_perm.mode 注意此命令只有具備以下條件的進程才可以請求: 1.進程的用戶ID等於shm_perm.cuid或者等於shm_perm.uid 2.超級用戶特權進程
IPC_RMID 刪除shm_id所指向的共享內存段,只有當shmid_ds結構的shm_nattch域為零時,才會真正執行刪除命令,否則不會刪除該段 注意此命令的請求規則與IPC_SET命令相同
SHM_LOCK 鎖定共享內存段在內存,此命令只能由超級用戶請求
SHM_UNLOCK 對共享內存段解鎖,此命令只能由超級用戶請求
使用函數shmat將一個存在的共享內存段連接到本進程空間,其函數原型如下: #include <sys/shm.h> void *shmat( int shm_id, const void *addr, int flag ); 函數中參數shm_id指定要引入的共享內存,參數addr與flag組合說明要引入的地址值,通常只有2種用法,addr為0,表明讓內核來決定第1個可以引入的位置。addr非零,並且flag中指定SHM_RND,則此段引入到addr所指向的位置(此操作不推薦使用,因為不會只對一種硬體上運行應用程序,為了程序的通用性推薦使用第1種方法),在flag參數中可以指定要引入的方式(讀寫方式指定)。 %說明:函數成功執行返回值為實際引入的地址,失敗返回–1。shmat函數成功執行會將shm_id段的shmid_ds結構的shm_nattch計數器的值加1。 當對共享內存段操作結束時,應調用shmdt函數,作用是將指定的共享內存段從當前進程空間中脫離出去。函數原型如下: #include <sys/shm.h> int shmdt( void *addr); 參數addr是調用shmat函數的返回值,函數執行成功返回0,並將該共享內存的shmid_ds結構的shm_nattch計數器減1,失敗返回–1。 下面實例演示了操作共享內存段的流程。程序的開始部分先檢測用戶是否有輸入,如出錯則列印該命令的使用幫助。接下來從命令行讀取將要引入的共享內存ID,使用shmat函數引入該共享內存,並在分離該內存之前睡眠3秒以方便查看系統IPC狀態。 (1)在vi編輯器中編輯該程序如下: 程序清單14-9 opr_shm.c 操作共享內存段 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> int main ( int argc, char *argv[] ) { int shm_id ; char * shm_buf; if ( argc != 2 ){ /* 命令行參數錯誤 */ printf ( "USAGE: atshm <identifier>" ); /*列印幫助消息*/ exit (1 ); } shm_id = atoi(argv[1]); /*得到要引入的共享內存段*/ /*引入共享內存段,由內核選擇要引入的位置*/ if ( (shm_buf = shmat( shm_id, 0, 0)) < (char *) 0 ){ perror ( "shmat" ); exit (1); } printf ( " segment attached at %p\n", shm_buf ); /*輸出導入的位置*/ system("ipcs -m"); sleep(3); /* 休眠 */ if ( (shmdt(shm_buf)) < 0 ) { /*與導入的共享內存段分離*/ perror ( "shmdt"); exit(1); } printf ( "segment detached \n" ); system ( "ipcs -m " ); /*再次查看系統IPC狀態*/ exit ( 0 ); } (2)在shell中編譯該程序如下: $gcc opr_shm.c–o opr_shm (3)在shell中運行該程序如下: $./ opr_shm 2752516 segment attached at 0xb7f29000 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 1 segment detached ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中從命令行中讀取所要引入的共享內存ID,並使用shmat函數引入該內存到當前的進程空間中。注意在使用shmat函數時,將參數addr的值設為0,所表達的意義是由內核來決定該共享內存在當前進程中的位置。由於在編程的過程中,很少會針對某一個特定的硬體或系統編程,所以由內核決定引入位置也就是shmat推薦的使用方式。在導入後使用shell命令ipcs –m來顯示當前的系統IPC的狀態,可以看出輸出信息中nattch欄位為該共享內存時的引用值,最後使用shmdt函數分離該共享內存並列印系統IPC的狀態。
編輯本段共享內存使用注意事項
共享內存相比其他幾種方式有著更方便的數據控制能力,數據在讀寫過程中會更透明。當成功導入一塊共享內存後,它只是相當於一個字元串指針來指向一塊內存,在當前進程下用戶可以隨意的訪問。缺點是,數據寫入進程或數據讀出進程中,需要附加的數據結構控制,共享內存通信數據結構示意如圖14-9所示。
編輯本段結構示意
%說明:圖中兩個進程同時遵循一定的規則來讀寫該內存。同時,在多進程同步或互斥上也需要附加的代碼來輔助共享內存機制。 在共享內存段中都是以字元串的默認結束符為一條信息的結尾。每個進程在讀寫時都遵守這個規則,就不會破壞數據的完整性。

6. java共享內存的問題,如何存,取共享數據

1 共享內存對應應用開發的意義
對熟知UNIX系統應用開發的程序員來說,IPC(InterProcess
Communication)機制是非常熟悉的,IPC基本包括共享內存、信號燈操作、消息隊列、信號處理等部分,是開發應用中非常重要的必不可少的工具。其中共享內存IPC機制的關鍵,對於數據共享、系統快速查詢、動態配置、減少資源耗費等均有獨到的優點。

對應UNIX系統來說,共享內存分為一般共享內存和映像文件共享內存兩種,而對應 Windows,實際上只有映像文件共享內存一種。所以java應用中也是只能創建映像文件共享內存。

在java語言中,基本上沒有提及共享內存這個概念,但是,在某一些應用中,共享內存確實非常有用,例如採用java語言的分布式應用系統中,存在著大量的分布式共享對象,很多時候需要查詢這些對象的狀態,以查看系統是否運行正常或者了解這些對象的目前的一些統計數據和狀態。如果採用網路通信的方式,顯然會增加應用的額外負擔,也增加了一些不必要的應用編程。而如果採用共享內存的方式,則可以直接通過共享內存查看對象的狀態數據和統計數據,從而減少了一些不必要的麻煩。

7. 共享內存是什麼意思

共享內存也說顯卡顯存,指在多處理器的計算機系統中,可以被不同中央CPU訪問的大容量內存。由於多個CPU需要快速訪問存儲器,這樣就要對存儲器進行緩存。任何一個緩存的數據被更新後,由於其他處理器也可能要存取,共享內存就需要立即更新,否則不同的處理器可能用到不同的數據。共享內存是Unix下的多進程之間的通信方法,這種方法通常用於一個程序的多進程間通信,實際上多個程序間也可以通過共享內存來傳遞信息。

8. linux共享內存和mmap的區別

共享內存的創建
根據理論:
1. 共享內存允許兩個或多個進程共享一給定的存儲區,因為數據不需要來回復制,所以是最快的一種進程間通信機制。共享內存可以通過mmap()映射普通文件(特殊情況下還可以採用匿名映射)機制實現,也可以通過系統V共享內存機制實現。應用介面和原理很簡單,內部機制復雜。為了實現更安全通信,往往還與信號燈等同步機制共同使用。

mmap的機制如:就是在磁碟上建立一個文件,每個進程存儲器裡面,單獨開辟一個空間來進行映射。如果多進程的話,那麼不會對實際的物理存儲器(主存)消耗太大。

shm的機制:每個進程的共享內存都直接映射到實際物理存儲器裡面。

結論:

1、mmap保存到實際硬碟,實際存儲並沒有反映到主存上。優點:儲存量可以很大(多於主存)(這里一個問題,需要高手解答,會不會太多拷貝到主存裡面???);缺點:進程間讀取和寫入速度要比主存的要慢。

2、shm保存到物理存儲器(主存),實際的儲存量直接反映到主存上。優點,進程間訪問速度(讀寫)比磁碟要快;缺點,儲存量不能非常大(多於主存)

使用上看:如果分配的存儲量不大,那麼使用shm;如果存儲量大,那麼使用shm。

參看網路:http://ke..com/view/1499209.htm
mmap就是一個文件操作

看這些網路的描述:
mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以向訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。 成功執行時,mmap()返回被映射區的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值 EACCES:訪問出錯EAGAIN:文件已被鎖定,或者太多的內存已被鎖定EBADF:fd不是有效的文件描述詞EINVAL:一個或者多個參數無效 ENFILE:已達到系統對打開文件的限制ENODEV:指定文件所在的文件系統不支持內存映射ENOMEM:內存不足,或者進程已超出最大內存映射數量 EPERM:權能不足,操作不允許ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志SIGSEGV:試著向只讀區寫入 SIGBUS:試著訪問不屬於進程的內存區參數fd為即將映射到進程空間的文件描述字,

一般由open()返回,同時,fd可以指定為-1,此時須指定 flags參數中的MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創建及打開,很顯然只能用於具有親緣關系的進程間通信)

相關文章參考:
mmap函數是unix/linux下的系統調用,來看《Unix Netword programming》卷二12.2節有詳細介紹。
mmap系統調用並不是完全為了用於共享內存而設計的。它本身提供了不同於一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統V的共享內存IPC則純粹用於共享目的,當然mmap()實現共享內存也是其主要應用之一。
mmap系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以像訪問普通內存一樣對文件進行訪問,不必再 調用read(),write()等操作。mmap並不分配空間, 只是將文件映射到調用進程的地址空間里, 然後你就可以用memcpy等操作寫文件, 而不用write()了.寫完後用msync()同步一下, 你所寫的內容就保存到文件里了. 不過這種方式沒辦法增加文件的長度, 因為要映射的長度在調用mmap()的時候就決定了.

簡單說就是把一個文件的內容在內存裡面做一個映像,內存比磁碟快些。
基本上它是把一個檔案對應到你的virtual memory 中的一段,並傳回一個指針。

重寫總結:
1、mmap實際就是操作「文件」。
2、映射文件,除了主存的考慮外。shm的內存共享,效率應該比mmap效率要高(mmap通過io和文件操作,或「需要寫完後用msync()同步一下」);當然mmap映射操作文件,比直接操作文件要快些;由於多了一步msync應該可以說比shm要慢了吧???
3、另一方面,mmap的優點是,操作比shm簡單(沒有調用比shm函數復雜),我想這也是許多人喜歡用的原因,包括nginx。

缺點,還得通過實際程序測試,確定!!!

修正理解(這也真是的,這個網站沒辦法附加;只能重寫了):
今天又細心研究了一下,發現網路這么一段說明:
2、系統調用mmap()用於共享內存的兩種方式:
(1)使用普通文件提供的內存映射:適用於任何進程之間;此時,需要打開或創建一個文件,然後再調用mmap();典型調用代碼如下:
fd=open(name, flag, mode);
if(fd<0)
...
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通過mmap()實現共享內存的通信方式有許多特點和要注意的地方,我們將在範例中進行具體說明。
(2)使用特殊文件提供匿名內存映射:適用於具有親緣關系的進程之間;由於父子進程特殊的親緣關系,在父進程中先調用mmap(),然後調用fork()。那麼在調用fork()之後,子進程繼承父進程匿名映射後的地址空間,同樣也繼承mmap()返回的地址,這樣,父子進程就可以通過映射區域進行通信了。注意,這里不是一般的繼承關系。一般來說,子進程單獨維護從父進程繼承下來的一些變數。而mmap()返回的地址,卻由父子進程共同維護。
看了一下windows「內存映射文件」:http://ke..com/view/394293.htm
內存映射文件與虛擬內存有些類似,通過內存映射文件可以保留一個地址空間的區域,同時將物理存儲器提交給此區域,只是內存文件映射的物理存儲器來自一個已經存在於磁碟上的文件,而非系統的頁文件,而且在對該文件進行操作之前必須首先對文件進行映射,就如同將整個文件從磁碟載入到內存。由此可以看出,使用內存映射文件處理存儲於磁碟上的文件時,將不必再對文件執行I/O操作,這意味著在對文件進行處理時將不必再為文件申請並分配緩存,所有的文件緩存操作均由系統直接管理,由於取消了將文件數據載入到內存、數據從內存到文件的回寫以及釋放內存塊等步驟,使得內存映射文件在處理大數據量的文件時能起到相當重要的作用。另外,實際工程中的系統往往需要在多個進程之間共享數據,如果數據量小,處理方法是靈活多變的,如果共享數據容量巨大,那麼就需要藉助於內存映射文件來進行。實際上,內存映射文件正是解決本地多個進程間數據共享的最有效方法。

這里再總結一次:
1、mmap有兩種方式,一種是映射內存,它把普通文件映射為實際物理內存頁,訪問它就和訪問物理內存一樣(這也就和shm的功能一樣了)(同時不用刷新到文件)
2、mmap可以映射文件,不確定會不會像windows「內存映射文件」一樣的功能,如果是,那麼他就能映射好幾G甚至好幾百G的內存數據,對大數據處理將提供強大功能了???
3、shm只做內存映射,和mmap第一個功能一樣!只不過不是普通文件而已,但都是物理內存。

9. linux共享內存使用的過程

Linux共享內存使用的過程?

一、什麼是共享內存
顧名思義,共享內存就是允許兩個不相關的進程訪問同一個邏輯內存。共享內存是在兩個正在運行的進程之間共享和傳遞數據的一種非常有效的方式。不同進程之間共享的內存通常安排為同一段物理內存。進程可以將同一段共享內存連接到它們自己的地址空間中,所有進程都可以訪問共享內存中的地址,就好像它們是由用C語言函數malloc分配的內存一樣。而如果某個進程向共享內存寫入數據,所做的改動將立即影響到可以訪問同一段共享內存的任何其他進程。

特別提醒:共享內存並未提供同步機制,也就是說,在第一個進程結束對共享內存的寫操作之前,並無自動機制可以阻止第二個進程開始對它進行讀取。所以我們通常需要用其他的機制來同步對共享內存的訪問,例如前面說到的信號量。

二、共享內存的使用
與信號量一樣,在Linux中也提供了一組函數介面用於使用共享內存,而且使用共享共存的介面還與信號量的非常相似,而且比使用信號量的介面來得簡單。它們聲明在頭文件 sys/shm.h中。
1、shmget函數
該函數用來創建共享內存,它的原型為:
int shmget(key_t key, size_t size, int shmflg);
第一個參數,與信號量的semget函數一樣,程序需要提供一個參數key(非0整數),它有效地為共享內存段命名,shmget函數成功時返回一個與key相關的共享內存標識符(非負整數),用於後續的共享內存函數。調用失敗返回-1.

不相關的進程可以通過該函數的返回值訪問同一共享內存,它代表程序可能要使用的某個資源,程序對所有共享內存的訪問都是間接的,程序先通過調用shmget函數並提供一個鍵,再由系統生成一個相應的共享內存標識符(shmget函數的返回值),只有shmget函數才直接使用信號量鍵,所有其他的信號量函數使用由semget函數返回的信號量標識符。

第二個參數,size以位元組為單位指定需要共享的內存容量

第三個參數,shmflg是許可權標志,它的作用與open函數的mode參數一樣,如果要想在key標識的共享內存不存在時,創建它的話,可以與IPC_CREAT做或操作。共享內存的許可權標志與文件的讀寫許可權一樣,舉例來說,0644,它表示允許一個進程創建的共享內存被內存創建者所擁有的進程向共享內存讀取和寫入數據,同時其他用戶創建的進程只能讀取共享內存。

熱點內容
淘寶為什麼官方店貴 發布:2025-01-16 02:33:09 瀏覽:766
我的蘋果四s為什麼充電沒有反應 發布:2025-01-16 02:31:53 瀏覽:610
電腦上軟體為什麼這么難卸 發布:2025-01-16 02:31:45 瀏覽:549
藝術體操為什麼只有女生參加 發布:2025-01-16 02:30:18 瀏覽:220
小米喇叭為什麼聲音小 發布:2025-01-16 02:22:32 瀏覽:50
廚房煙感器為什麼晚上一直響 發布:2025-01-16 02:14:47 瀏覽:416
ps軟體尺寸為什麼是寬高定義 發布:2025-01-16 02:13:29 瀏覽:863
為什麼回家的時間總是很短 發布:2025-01-16 02:07:04 瀏覽:952
為什麼蛙泳老是游不好 發布:2025-01-16 02:06:58 瀏覽:583
為什麼看腰就能看出生過孩子沒 發布:2025-01-16 01:56:14 瀏覽:232