در قسمت های قبل در مورد پایپ و به اشتراک گذاری حافظه در پراسس ها به اندازه کافی صحبت شد . اما در اون روش ما یک کپی از دیتا رو در اختیار پراسس های دیگر قرار میدادیم .

در این قسمت تصمیم داریم تا از روش دیگری استفاده کنیم ، در این روش ما یک آدرس از دیتای مورد نظر خودمون رو بین دو یا چند پراسس به اشتراک میگذاریم(بدون کپی کردن). بدلیل این که کپیی از آنها تهیه نمیکنیم سرعت انتقال بسیار بیشتر از استفاده از پایپ میبشد . اما باید این نکته را نیز در نظر داشت در انتقال حجم های کم این روش میتواند باعث افزایش بی دلیل داده گردد ، دلیل آن هم این است که چون مثلا پیج های حافظه ( اغلب ) به اندازه 4 کیلوبایت میباشد ،اگر ما داده ای را که به اندازه 3 کیلو بایت است را بین پروسس ها شیر کنیم ، مقدار 4 کیلوبایت شیر میگردد (چون هر پیج دارای 4 کیلوبایت است ) ، و بنابر این یک کیلوبایت اضافه شیر میگردد .


HANDLE WINAPI CreateFileMapping(
  _In_     HANDLE                hFile,
  _In_opt_ LPSECURITY_ATTRIBUTES lpAttributes,
  _In_     DWORD                 flProtect,
  _In_     DWORD                 dwMaximumSizeHigh,
  _In_     DWORD                 dwMaximumSizeLow,
  _In_opt_ LPCTSTR               lpName
);
LPVOID WINAPI MapViewOfFile(
  _In_ HANDLE hFileMappingObject,
  _In_ DWORD  dwDesiredAccess,
  _In_ DWORD  dwFileOffsetHigh,
  _In_ DWORD  dwFileOffsetLow,
  _In_ SIZE_T dwNumberOfBytesToMap
);
void CopyMemory(
  _In_       PVOID  Destination,
  _In_ const VOID   *Source,
  _In_       SIZE_T Length
);


Shared Memory


برای اشتراک دیتا ، باید با سه api آشناباشید که مختصری از آن را توضیح میدهیم.

CreateFileMapping :
وظیفه این تابع ایجاد یا باز کردن یک فایل که برای اشتراک دیتا میباشد را بسازد (یا باز کند).
  1. آرگمان اول یک هندل را دریافت میکند که برای ایجاد یک فایل برای اشتراک میباشد . توجه داشته باشید که اگر فلگ INVALID_HANDLE_VALUE را به پارامت اول ارسال کنید باید سایز فایل را در پارامتر چهارم و پنجم تنظیم کنید .
  2. آرگمان دوم برای تنظیمات بخش امنیتی شیر مموری هست . اگر نال تنظیم شود مقدار پیش فرض را میگیرد.
  3. آرگمان سوم برای تنظیم حالت خواندن و نوشتن دارد (برای دیدن لیست فلگ ها میتوانید به سایت msdn مراجعه کنید).
  4. پارامتر آخر نام فایلی میباشد که به اشتراک گذاشته میشود . اگر دارای مقدار نال باشد یک فایل اشتراکی بدون نام ساخته میشود ، در صورتی که نام استفاده از قبل در event, semaphore, mutex, waitable timer,job object استفاده شده باشد تابع دچار شکست میشود و با تابع GetLastError نیز میتوان خطای آن را مشاهده کرد.(ERROR_INVALID_HANDLE)
در صورت موفقیت ، تابع یک هندل برای کنترل فایل شیر شده باز میگرداند ، اگر آدرس از قبل موجود باشد تابع هندل آن را برمیگرداند(میشه گفت آن را باز میکند !) ، در غیر این صورت اگر تابع به هر دلیلی موفق نشود مقدار نال را برمی گرداند ، که ارور آن را میتوان با تابع GetLastError گرفت .(ERROR_ALREADY_EXISTS)


MapViewOfFile:

وظیفه این تابع آوردن آدرس فایل های شیر شده ، در داخل آدرس پراسس فراخواننده این تابع.

  1. آرگمان اول هندلی که  توسط دو تابع ساخت یا باز کردن شیر مموری را میگیرد.
  2. آرگمان دوم نوع دسترسی به فایل ها را تعیین میکند که بصورت چندین فلگ میباشد . لیست این فلگ ها در msdn موجود است.
این تابع آدرسی را بازمیگرداند که شامل دیتاهای به اشتراک گذاشته شده میباشد.


CopyMemory:

وظیفه این تابع کپی کردن یک مقدار از جایی به جایی دیگر از حافظه میباشد .

  1. آرگمان اول یک اشاره گر به آدرس اولیه مقصد بلوک کپی شده میباشد.
  2. آرگمان دوم یک اشاره گر به آدرس اولیه بلوک حافظه برای کپی میباشد.
  3. سایز بلوکی است که برای به اشتراک گذاشته شدن میباشد.( بر حسب بایت)

برنامه نمونه :
در برنامه اول یک استراکچر رو با api های گفته شده در آدرسی به اشتراک میگذاریم و سپس در برنامه دوم آن را درون یک استراکچر با همان ساختار ولی با مقادیر متفاوت مساوی میگذاریم تا انتقال دیتا را از پراسس اول به پراسس دوم مشاهده کنیم (هر دو پراسس باید کنار هم اجرا شوند و برنامه اول باید اول ران گردد )

برنامه اول :

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string>
#include <iostream>
using namespace std;
#define BUF_SIZE 256

struct share
{
int num= 0;
string str = "hi";
};
int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;
share sh1;

hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, BUF_SIZE, TEXT("Global\\Amid"));

if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n")
, GetLastError());
return 1;
}

pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS,
0, 0, BUF_SIZE);

if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n")
, GetLastError());
CloseHandle(hMapFile);
return 1;
}
CopyMemory((PVOID)pBuf, &sh1, (sizeof(share)));
_getch();

UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}

برنامه دوم :

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#include <string>
using namespace std;
#define BUF_SIZE 256

struct share
{
int num = 1;
string str = "by";
};

int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;
share *sh2 = new share;

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,
FALSE, TEXT("Global\\Amid"));

if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n")
, GetLastError());
return 1;
}

pBuf = (LPCTSTR)MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);

if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n")
, GetLastError());
CloseHandle(hMapFile);
return 1;
}

sh2 = (share*)pBuf;

cout << sh2->num;
cout << sh2->str;

_getch();
delete sh2;
sh2 = NULL;
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}