Shared memory for process communication

Shared memory definition

In software, the term shared memory refers to memory that can be accessed by multiple processes. A process is a single running instance of a program. In this case, shared memory is used for inter-process communication

Shared memory in Qt

Use shared memory between two processes

QtTest.h

#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtTest.h"
#include <QSharedMemory>//共享内存头文件
class QtTest : public QWidget
{
    
    
    Q_OBJECT

public:
    QtTest(QWidget *parent = Q_NULLPTR);
private:
	void setUpConnecitons();
private slots :
		void onButtonWrite(bool value);
		void onButtonRead(bool value);
private:
    Ui::QtTestClass ui;
	QSharedMemory _sharedMemory;
};

QtTest.cpp

#include "QtTest.h"
#include <QBuffer>
#include <QDebug>
QtTest::QtTest(QWidget *parent)
	: QWidget(parent)
	, _sharedMemory("QSharedMemoryTest")//指定共享内存的key值为 QSharedMemoryTest
	//必须给定一个key值 且唯一
{
    
    
	ui.setupUi(this);
	setUpConnecitons();
	qDebug() << "QtTest QtTest";
}

void QtTest::setUpConnecitons()
{
    
    
	connect(ui.pushButtonWrite, &QPushButton::clicked, this,&QtTest::onButtonWrite);
	connect(ui.pushButtonRead, &QPushButton::clicked, this, &QtTest::onButtonRead);
}

void QtTest::onButtonWrite(bool value)
{
    
    
	if (_sharedMemory.isAttached())//判断是否已经附加共享内存
	{
    
    
		_sharedMemory.detach();//解除对共享内存的附加
	}
	QBuffer buffer;
	buffer.open(QBuffer::ReadWrite);
	auto text = ui.lineEditWrite->text();
	QDataStream out(&buffer);
	out << text;//
	int size = buffer.size();
	qDebug() << "Write:---" << text<<"---Size--:"<<size;
	if (!_sharedMemory.create(size)) {
    
    //创建一块共享内存
		qDebug() << "Error:---"<<_sharedMemory.errorString();
		return;
	}
	_sharedMemory.lock();
	char *to = (char*)_sharedMemory.data();
	const char *from = buffer.data().data();
	memcpy(to, from, qMin(_sharedMemory.size(), size));

	_sharedMemory.unlock();
}

void QtTest::onButtonRead(bool value)
{
    
    
	if (!_sharedMemory.attach()) //附加到共享内存
	{
    
    
		qDebug() << "Attach Falied";
		return;
	}
	QBuffer buffer;
	QDataStream in(&buffer);
	_sharedMemory.lock();
	buffer.setData((char*)_sharedMemory.constData(), _sharedMemory.size());//读取共享内存中的数据  读取完之后并不会清空共享内存中的数据
	buffer.open(QBuffer::ReadOnly);
	QString text;
	in >> text;
	qDebug() << "Read:---" << text;
	_sharedMemory.unlock();
	ui.lineEditRead->setText(text);
	_sharedMemory.detach();
}

Interface:
Insert picture description here
The main function of this program is: click the Write button to write the content in the above QLineEdit to the shared memory. Click the read button to read the data in the shared content to the QLineEdit below.
note

  • When creating shared memory, you must specify a key value, and the key value is unique. See the constructor for the above example
  • Must be attached to shared memory before communication
  • When writing and reading data to the shared memory, you need to lock it, and unlock it after the operation is complete. That is the lock and unlock in the above example.

Use shared memory between parent and child processes

Shared memory under windows

Source of this section: https://www.cnblogs.com/xiekeli/p/4018579.html
Shared memory under windows is realized through FileMapping (memory mapping file). It is the mapping from a file to a piece of memory. (Operations on large files are generally handled in the form of memory-mapped files). Map the file to memory first (as if loading the entire file from disk to memory). After that, it is unnecessary to perform I/O operations when operating on this file. Improved execution speed.

Shared memory implementation steps
  • Call CreateFileMapping to create a memory file mapping object
HANDLE CreateFileMapping(
  HANDLE hFile,              // handle to file to map
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
                             // optional security attributes
  DWORD flProtect,           // protection for mapping object
  DWORD dwMaximumSizeHigh,   // high-order 32 bits of object size
  DWORD dwMaximumSizeLow,    // low-order 32 bits of object size
  LPCTSTR lpName             // name of file-mapping object
);

Through this API function, a kernel object of a memory-mapped file will be created, which is used to map the file to the memory. Like virtual memory, memory-mapped files can be used to reserve an area of ​​the address space and commit physical memory
to that area. The difference between them is that the physical memory comes from a file that is already on the disk, rather than the system page file
hFile : it is used to identify the file handle you want to map to the process address space. The handle can be returned by calling the C reate File function. Here, we don’t need an actual file, so we don’t need to call CreateFile to create a file. The hFile parameter can be filled with INVALID_HANDLE_VALUE;
lpFileMappingAttributes : The parameter is a pointer to the SECURITY_ATTRIBUTES structure of the file mapping kernel object, and the value usually passed is NULL ;
FlProtect : Security settings for memory mapped files (PAGE_READONLY opens the mapping in read-only mode; PAGE_READWRITE opens the mapping in readable and writable mode; PAGE_WRITECOPY leaves a backup for write operations)
dwMaximumSizeHigh : the upper 32 bits of the maximum length of the file mapping.
dwMaximumSizeLow : The lower 32 bits of the maximum length of the file mapping. If this parameter and dwMaximumSizeHigh are both zero, the actual length of the disk file is used.
lpName : Specify the name of the file mapping object, and other processes can use this name to call OpenFileMapping to open the FileMapping object.
If the creation is successful, the handle of the created memory-mapped file is returned, if it already exists, the handle is also returned, but the error code returned by calling GetLastError() is: 183 (ERROR_ALREADY_EXISTS), if the creation fails, NULL is returned;

  • Call MapViewOfFile to map to the virtual address of the current process ;
    if the call to CreateFileMapping is successful, call the MapViewOfFile function to map the memory-mapped file to the virtual address of the process
LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,  // file-mapping object to map into 
                              // address space
  DWORD dwDesiredAccess,      // access mode
  DWORD dwFileOffsetHigh,     // high-order 32 bits of file offset
  DWORD dwFileOffsetLow,      // low-order 32 bits of file offset
  DWORD dwNumberOfBytesToMap  // number of bytes to map
);
hFileMappingObject:CreateFileMapping()返回的文件映像对象句柄。
dwDesiredAccess: 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。
dwFileOffsetHigh: 表示文件映射起始偏移的高32.
dwFileOffsetLow: 表示文件映射起始偏移的低32.
dwNumberOfBytesToMap :文件中要映射的字节数。为0表示映射整个文件映射对象。
  • Open the corresponding memory mapping object
    in the receiving process. In the data receiving process, first call the OpenFileMapping() function to open a named file mapping kernel object, and get the corresponding file mapping kernel object handle hFileMapping; if the opening is successful, call MapViewOfFile() A view of the function mapping object, which maps the file mapping kernel object hFileMapping to the process address of the current application for reading. (Of course, if you use CreateFileMapping here, you can also get the corresponding handle)
HANDLE OpenFileMapping(
  DWORD dwDesiredAccess,  // access mode
  BOOL bInheritHandle,    // inherit flag
  LPCTSTR lpName          // pointer to name of file-mapping object
);
dwDesiredAccess:同MapViewOfFile函数的dwDesiredAccess参数
bInheritHandle :如这个函数返回的句柄能由当前进程启动的新进程继承,则这个参数为TRUE。
lpName :指定要打开的文件映射对象名称。
  • Read and write memory mapped files
    Once the MapViewOfFile call is successful, you can read and write memory just like reading and writing the memory area of ​​the address space of the process.
//读操作:
if ( m_pViewOfFile  )
{
    
    
        // read text from memory-mapped file
        TCHAR s[dwMemoryFileSize];
        
        lstrcpy(s, (LPCTSTR) m_pViewOfFile);
}
//写操作:
if ( m_pViewOfFile )
 {
    
    
        TCHAR s[dwMemoryFileSize];
        m_edit_box.GetWindowText(s, dwMemoryFileSize);
            
        lstrcpy( (LPTSTR) m_pViewOfFile, s);
            
        // Notify all running instances that text was changed
        ::PostMessage(HWND_BROADCAST, 
            wm_Message,     
            (WPARAM) m_hWnd,
            0);    
}
  • Clean up the kernel object
    After it is used up, it is necessary to cancel the mapping of the address space of the process and release the memory mapped object.
    //取消本进程地址空间的映射;   
    UnmapViewOfFile(pLocalMem);  
    pLocalMem=NULL;   
    //关闭文件映射内核文件  
    CloseHandle(hFileMapping);
Instance
note

The conflict between writing and writing is not well resolved. The memory-mapped file is a shared resource. There must be a synchronization problem in reading and writing of multiple processes. Maybe there will be no problem in this example, but there is a higher problem in the actual project. In the case of concurrent reading and writing of frequency, the synchronization of reading and writing must be carried out

Read and write synchronization

Guess you like

Origin blog.csdn.net/weixin_39308337/article/details/108700507