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:
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