【C++】Windows下共享内存加信号量实现进程间同步通信

这篇具有很好参考价值的文章主要介绍了【C++】Windows下共享内存加信号量实现进程间同步通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一,函数清单

1.CreateFileMapping 方法

2.OpenFileMapping 方法

3.MapViewOfFile 方法

4.UnmapViewOfFile 方法

5.CreateSemaphore 方法

6. OpenSemaphore 方法

7.WaitForSingleObject 方法

8.ReleaseSemaphore 方法

9.CloseHandle 方法

10.GetLastError 方法

二,单共享内存单信号量-进程间单向通信

共享内存管理文件实现 

A进程调用接口实现写操作

B进程调用接口实现读操作

三,单共享内存双信号量-进程间单向通信

共享内存管理文件实现

A进程调用接口实现写操作

B进程调用接口实现读操作

四,双共享内存双信号量-进程间双向通信


一,函数清单

1.CreateFileMapping 方法

HANDLE CreateFileMapping(
  [in]           HANDLE                hFile,
  [in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
  [in]           DWORD                 flProtect,
  [in]           DWORD                 dwMaximumSizeHigh,
  [in]           DWORD                 dwMaximumSizeLow,
  [in, optional] LPCWSTR               lpName
);

功能

  • 创建或打开命名或未命名的共享内存对象。

参数

  • hFile:创建共享内存则设置为 INVALID_HANDLE_VALUE,并且还必须为 dwMaximumSizeHigh 和 dwMaximumSizeLow 参数中的文件映射对象指定大小
  • lpFileMappingAttributes:共享内存对象的安全属性,通常设置为 NULL,则子进程无法继承句柄,并且共享内存对象获取默认的安全描述符。
  • flProtect:指定共享内存对象的访问方式。通常设置为 PAGE_EXECUTE_READWRITE,表示可进行只读、写入复制、读/写或执行访问。
  • dwMaximumSizeHigh:高位字节大小,通常设置为0。
  • dwMaximumSizeLow:地位字节大小,设置共享内存段的大小。
  • lpName:共享内存对象的标识名称。

返回值

  • 如果函数成功,则返回值是新创建的共享内存对象的句柄。
  • 如果该对象在函数调用之前存在,则函数将返回现有对象的句柄 (其当前大小,而不是指定的大小) , GetLastError 返回 ERROR_ALREADY_EXISTS
  • 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

2.OpenFileMapping 方法

HANDLE OpenFileMapping(
  [in] DWORD   dwDesiredAccess,
  [in] BOOL    bInheritHandle,
  [in] LPCWSTR lpName
);

功能

  • 打开命名共享内存对象。

参数

  • dwDesiredAccess:对共享内存对象的访问方式。用于共享内存段的保护,通常设置为 FILE_MAP_ALL_ACCESS,可执行所有访问权限。
  • bInheritHandle:如果此参数为 TRUE, 则 CreateProcess 函数创建的进程可以继承句柄;否则,无法继承句柄。
  • lpName:要打开的共享内存对象的标识名称。

返回值

  • 如果函数成功,则返回值是指定共享内存对象的打开句柄。
  • 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

3.MapViewOfFile 方法

LPVOID MapViewOfFile(
  [in] HANDLE hFileMappingObject,
  [in] DWORD  dwDesiredAccess,
  [in] DWORD  dwFileOffsetHigh,
  [in] DWORD  dwFileOffsetLow,
  [in] SIZE_T dwNumberOfBytesToMap
);

功能

  • 将共享内存映射到调用进程的地址空间。

参数

  •  hFileMappingObject:共享内存对象的句柄。 CreateFileMapping 和 OpenFileMapping 函数返回此句柄。
  • dwDesiredAccess:对共享内存对象的访问方式,通常指定为FILE_MAP_ALL_ACCESS,表示可读可写。
  • dwFileOffsetHigh:高位字节大小,通常设置为0。
  • dwFileOffsetLow:地位字节大小,通常设置为0。
  • dwNumberOfBytesToMap:要映射到共享内存段的字节数。 

返回值

  • 如果函数成功,则返回值为共享内存段的起始地址。
  • 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

4.UnmapViewOfFile 方法

BOOL UnmapViewOfFile(
  [in] LPCVOID lpBaseAddress
);

功能

  • 从调用进程的地址空间取消映射共享内存段。

参数

  • lpBaseAddress:指向要取消映射的共享内存指针。此值必须与上一次调用MapViewOfFile 函数返回的值相同。

返回值

  • 如果该函数成功,则返回值为非零值。
  • 如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

5.CreateSemaphore 方法

HANDLE CreateSemaphore(
  [in, optional] LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  [in]           LONG                  lInitialCount,
  [in]           LONG                  lMaximumCount,
  [in, optional] LPCWSTR               lpName
);

功能

  • 创建或打开命名或未命名的信号量对象。

参数

  • lpSemaphoreAttributes:信号量安全特征。通常指定为 NULL,但子进程无法继承句柄。
  • lInitialCount:信号量对象的初始可使用资源数目。 此值必须>=0,并且<=lMaximumCount。如果设置为0,信号量为未触发状态。
  • lMaximumCount:信号量对象的最大资源计数。 此值必须大于零。
  • lpName:信号量对象的名称。各进程实现同步会用到该名称。

返回值

  • 如果函数成功,则返回值是信号量对象的句柄。
  • 如果在函数调用之前存在相同命名的信号量对象,则函数将返回现有对象的句柄,GetLastError 返回 ERROR_ALREADY_EXISTS
  • 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

6. OpenSemaphore 方法

HANDLE OpenSemaphore(
  [in] DWORD   dwDesiredAccess,
  [in] BOOL    bInheritHandle,
  [in] LPCWSTR lpName
);

功能

  • 打开现有的命名信号量对象。

参数

  • dwDesiredAccess:对信号量对象的访问权限,通常指定为 SEMAPHORE_ALL_ACCESS
  • bInheritHandle:如果此值为 TRUE,则此过程创建的进程将继承句柄。 否则,进程不会继承此句柄。
  • lpName:打开已有的信号量名称。

返回值

  • 如果函数成功,则返回值是信号灯对象的句柄。
  • 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

7.WaitForSingleObject 方法

DWORD WaitForSingleObject(
  [in] HANDLE hHandle,
  [in] DWORD  dwMilliseconds
);

功能

  • 阻塞等待指定对象处于信号状态或超时间隔已过。

参数

  • hHandle:创建的信号量对象的句柄。
  • dwMilliseconds:超时间隔(以毫秒为单位)。通常指定为 INFINITE,表示仅当发出对象信号时,该函数才会返回。

返回值

  • 如果函数成功,则返回值指示导致函数返回的事件。可以是下列值之一
返回代码/值 描述

WAIT_ABANDONED

指定的对象是一个互斥对象,该对象不是由拥有互斥对象的线程在拥有线程终止之前释放的。 互斥对象所有权授予调用线程,互斥状态设置为非对齐状态。如果互斥体保护持久状态信息,则应检查该信息是否一致性。

WAIT_OBJECT_0

指定对象的状态已发出信号。

WAIT_TIMEOUT

超时间隔已过,对象的状态未对齐。

WAIT_FAILED

函数失败。 要获得更多的错误信息,请调用 GetLastError。

8.ReleaseSemaphore 方法

BOOL ReleaseSemaphore(
  [in]            HANDLE hSemaphore,
  [in]            LONG   lReleaseCount,
  [out, optional] LPLONG lpPreviousCount
);

功能

  • 按指定量增加指定的信号量对象的资源计数。

参数

  • hSemaphore:设置为 CreateSemaphore 或 OpenSemaphore 函数返回的信号量对象句柄。
  • lReleaseCount:信号量对象的当前资源计数将增加的量。该值必须>0且<=最大资源数量,通常设置为1。
  • lpPreviousCount:指向一个变量的指针,用于接收信号量的先前资源计数。如果不需要先前资源计数,此参数可以为 NULL 

返回值

  • 如果该函数成功,则返回值为非零值。
  • 如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

9.CloseHandle 方法

BOOL CloseHandle(
  [in] HANDLE hObject
);

功能

  • 关闭打开的对象句柄。

参数

  • hObject:打开对象的有效句柄。

返回值

  • 如果该函数成功,则返回值为非零值。
  • 如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

10.GetLastError 方法

_Post_equals_last_error_ DWORD GetLastError();

功能

  • 检索调用线程的最后错误代码值。 最后一个错误代码是按线程维护的。 多个线程不会覆盖彼此的最后错误代码。

返回值

  • 返回值是调用线程的最后错误代码。 

二,单共享内存单信号量-进程间单向通信

场景描述:实现进程间单向通信,只允许一块进程往该共享内存写入数据,另一个进程负责读数据,并使用信号量实现互斥操作,当有一个进程在进行写或读数据时,对该共享内存独占访问,其它进程必须阻塞等待该共享内存的信号量资源释放。

  • 开辟线程对共享内存进行管理。
  • 只有一个信号量,该信号量初始化只有一个可用资源。

共享内存管理文件实现 

头文件

#ifndef SHAREMEMORYMANAGER_H
#define SHAREMEMORYMANAGER_H

#include <QObject>
#include <QThread>
#include <Windows.h>

#include <QDebug>
#define cout qDebug() <<"["<<__FUNCTION__<<"]["<<__LINE__<<"]:"

class ShareMemoryManager : public QObject
{
    Q_OBJECT
public:
    explicit ShareMemoryManager(int shareMemorySize,const QString &shareMemoryKey
                                ,const QString &semaphoreKey,QObject *parent = nullptr);
    ~ShareMemoryManager();

    void startManager();    //开辟线程管理
    void quitManager();     //退出线程管理

private:
    void initShareMemory(const int &shareMemorySize,const QString &shareMemoryKey);
    void initSemaphore(const QString &semaphoreKey);

signals:
    void sig_readMessageFromShareMemory(QString message);

public slots:
    void slot_writeMessageToShareMemory(const QString &message);    //A进程进行写操作调用该接口
    void slot_readMessageFromShareMemory();                         //B进程进行读操作调用该接口

private:
    QThread *m_pThread;

    HANDLE m_pShareMemoryHandle;    //共享内存对象句柄
    LPVOID m_pShareMemoryBuffer;    //共享内存映射到本地

    HANDLE m_pSemaphoreForShareMem;     //共享内存信号量

    int m_shareMemorySize;      //共享内存段大小

    char *m_pReadBuf{nullptr};       //读缓冲区,用于读取共享内存的数据
};

#endif // SHAREMEMORYMANAGER_H

源文件

#include "ShareMemoryManager.h"

ShareMemoryManager::ShareMemoryManager(int shareMemorySize, const QString &shareMemoryKey
                                       , const QString &semaphoreKey, QObject *parent):QObject(parent)
{
    m_pThread = nullptr;
    startManager();
    initShareMemory(shareMemorySize,shareMemoryKey);
    initSemaphore(semaphoreKey);
}

ShareMemoryManager::~ShareMemoryManager()
{
    //释放信号量资源
    if (m_pSemaphoreForShareMem != nullptr) {
        ReleaseSemaphore(m_pSemaphoreForShareMem,1,NULL);
        CloseHandle(m_pSemaphoreForShareMem);
        m_pSemaphoreForShareMem = nullptr;
    }

    //释放共享内存资源:先解除文件映射,再关闭共享内存句柄
    if (m_pShareMemoryBuffer != nullptr) {
        UnmapViewOfFile(m_pShareMemoryBuffer);
        m_pShareMemoryBuffer = nullptr;
    }
    if (m_pShareMemoryHandle != nullptr) {
        CloseHandle(m_pShareMemoryHandle);
        m_pShareMemoryHandle = nullptr;
    }

    //释放读缓冲区指针
    if(m_pReadBuf != nullptr){
        free(m_pReadBuf);
        m_pReadBuf = nullptr;
    }

    quitManager();
}

void ShareMemoryManager::startManager()
{
    if(m_pThread == nullptr){
        m_pThread = new QThread;
        this->moveToThread(m_pThread);
        m_pThread->start();
    }
}

void ShareMemoryManager::quitManager()
{
    if(m_pThread != nullptr){
        m_pThread->requestInterruption();
        m_pThread->quit();
        m_pThread->wait();
        m_pThread->deleteLater();
        m_pThread = nullptr;
    }
}

void ShareMemoryManager::initShareMemory(const int &shareMemorySize, const QString &shareMemoryKey)
{
    m_shareMemorySize = shareMemorySize;
    m_pShareMemoryHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_EXECUTE_READWRITE,0,shareMemorySize,shareMemoryKey.toStdWString().c_str());
    if (m_pShareMemoryHandle == NULL)
    {
        cout << "Could not create file mapping B object:" << GetLastError();
        return;
    }

    m_pShareMemoryBuffer = MapViewOfFile(m_pShareMemoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, shareMemorySize);
    if (m_pShareMemoryBuffer == NULL)
    {
        cout << "Could not map view of file B:" << GetLastError();
        CloseHandle(m_pShareMemoryHandle);
        return;
    }
}

void ShareMemoryManager::initSemaphore(const QString &semaphoreKey)
{
    m_pSemaphoreForShareMem = CreateSemaphore(NULL, 1, 1, semaphoreKey.toStdWString().c_str());
    if (m_pSemaphoreForShareMem == NULL)
    {
        cout << "CreateSemaphore writeSemName error: %d" << GetLastError();
        return;
    }
}

void ShareMemoryManager::slot_writeMessageToShareMemory(const QString &message)
{
    DWORD semRet = WaitForSingleObject(m_pSemaphoreForShareMem,INFINITE);
    if(semRet == WAIT_OBJECT_0){
        strcpy_s((char*)m_pShareMemoryBuffer,m_shareMemorySize,message.toStdString().c_str());
        ReleaseSemaphore(m_pSemaphoreForShareMem,1,NULL);
    }
}

void ShareMemoryManager::slot_readMessageFromShareMemory()
{
    if(m_pReadBuf == nullptr){
        m_pReadBuf = (char*)malloc(m_shareMemorySize*sizeof(char));
    }
    memset(m_pReadBuf,0,m_shareMemorySize);

    DWORD semRet = WaitForSingleObject(m_pSemaphoreForShareMem,INFINITE);
    if (semRet == WAIT_OBJECT_0) {
        strcpy_s(m_pReadBuf,m_shareMemorySize,(char*)m_pShareMemoryBuffer);
        cout << QString(m_pReadBuf);    //打印读出来的数据
        emit sig_readMessageFromShareMemory(QString(m_pReadBuf));
        ReleaseSemaphore(m_pSemaphoreForShareMem,1,NULL);
    }
}

A进程调用接口实现写操作

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "ShareMemoryManager.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void sig_sendMessage(const QString &data);

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    ShareMemoryManager *m_pSMM;
};

#endif // MAINWINDOW_H

源文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_pSMM = new ShareMemoryManager(250,"shareMemory","Semaphore");
    connect(this,SIGNAL(sig_sendMessage(QString)),m_pSMM,SLOT(slot_writeMessageToShareMemory(QString)),Qt::ConnectionType::QueuedConnection);
}

MainWindow::~MainWindow()
{
    if(m_pSMM != nullptr){
        m_pSMM->deleteLater();
        m_pSMM = nullptr;
    }
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString data = ui->lineEdit->text();
    emit sig_sendMessage(data);
}

ui布局

【C++】Windows下共享内存加信号量实现进程间同步通信

B进程调用接口实现读操作

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "ShareMemoryManager.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void slot_readMessageToShow(QString message);   //显示从共享内存读取的数据

private:
    Ui::MainWindow *ui;

    ShareMemoryManager *m_pSMM;
};

#endif // MAINWINDOW_H

源文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_pSMM = new ShareMemoryManager(250,"shareMemory","Semaphore");
    connect(ui->pushButton,SIGNAL(clicked()),m_pSMM,SLOT(slot_readMessageFromShareMemory()),Qt::ConnectionType::QueuedConnection);
    connect(m_pSMM,SIGNAL(sig_readMessageFromShareMemory(QString)),this,SLOT(slot_readMessageToShow(QString)),Qt::ConnectionType::QueuedConnection);
}

MainWindow::~MainWindow()
{
    if(m_pSMM != nullptr){
        m_pSMM->deleteLater();
        m_pSMM = nullptr;
    }
    delete ui;
}

void MainWindow::slot_readMessageToShow(QString message)
{
    ui->plainTextEdit->appendPlainText(message);
}

ui布局

【C++】Windows下共享内存加信号量实现进程间同步通信 

三,单共享内存双信号量-进程间单向通信

场景描述:实现进程间单向通信,只允许一块进程往该共享内存写入数据,另一个进程负责读数据,并使用信号量实现互斥操作,A进程进行写操作完后会释放一个读信号量资源通知B进程进行读操作,A进程并阻塞在写信号量上。B进程进行读操作会消耗一个读信号量资源并释放一个写信号量资源,通知A进程进行下一轮写操作。

  • 开辟线程对共享内存进行管理。
  • 定义读写两个信号量,信号量初始化可用资源数都为0(所以在先调用WaitForSingleObject后调用ReleaseSemaphore会阻塞进程)。

共享内存管理文件实现

头文件

#ifndef SHAREMEMORYMANAGER_H
#define SHAREMEMORYMANAGER_H

#include <QObject>
#include <QThread>
#include <Windows.h>

#include <QDebug>
#define cout qDebug() <<"["<<__FUNCTION__<<"]["<<__LINE__<<"]:"

class ShareMemoryManager : public QObject
{
    Q_OBJECT
public:
    explicit ShareMemoryManager(int shareMemorySize,const QString &shareMemoryKey
                                ,const QString &readSemaphoreKey,const QString &writeSemaphoreKey
                                ,QObject *parent = nullptr);
    ~ShareMemoryManager();

    void startManager();    //开辟线程管理
    void quitManager();     //退出线程管理

private:
    void initShareMemory(const int &shareMemorySize,const QString &shareMemoryKey);
    void initSemaphore(const QString &readSemaphoreKey,const QString &writeSemaphoreKey);

signals:
    void sig_readMessageFromShareMemory(QString message);

public slots:
    void slot_writeMessageToShareMemory(const QString &message);    //A进程进行写操作调用该接口
    void slot_readMessageFromShareMemory();                         //B进程进行读操作调用该接口

private:
    QThread *m_pThread;

    HANDLE m_pShareMemoryHandle;    //共享内存对象句柄
    LPVOID m_pShareMemoryBuffer;    //共享内存映射到本地

    HANDLE m_pReadSemaphoreForShareMem;     //共享内存读信号量
    HANDLE m_pWriteSemaphoreForShareMem;    //共享内存写信号量

    int m_shareMemorySize;      //共享内存段大小

    char *m_pReadBuf{nullptr};  //读缓冲区,用于读取共享内存的数据
};

#endif // SHAREMEMORYMANAGER_H

源文件

#include "ShareMemoryManager.h"

ShareMemoryManager::ShareMemoryManager(int shareMemorySize, const QString &shareMemoryKey
                                       , const QString &readSemaphoreKey, const QString &writeSemaphoreKey, QObject *parent):QObject(parent)
{
    m_pThread = nullptr;
    startManager();
    initShareMemory(shareMemorySize,shareMemoryKey);
    initSemaphore(readSemaphoreKey,writeSemaphoreKey);
}

ShareMemoryManager::~ShareMemoryManager()
{
    //释放信号量资源
    if (m_pReadSemaphoreForShareMem != nullptr) {
        ReleaseSemaphore(m_pReadSemaphoreForShareMem,1,NULL);
        CloseHandle(m_pReadSemaphoreForShareMem);
        m_pReadSemaphoreForShareMem = nullptr;
    }
    if (m_pWriteSemaphoreForShareMem != nullptr) {
        ReleaseSemaphore(m_pWriteSemaphoreForShareMem,1,NULL);
        CloseHandle(m_pWriteSemaphoreForShareMem);
        m_pWriteSemaphoreForShareMem = nullptr;
    }

    //释放共享内存资源:先解除文件映射,再关闭共享内存句柄
    if (m_pShareMemoryBuffer != nullptr) {
        UnmapViewOfFile(m_pShareMemoryBuffer);
        m_pShareMemoryBuffer = nullptr;
    }
    if (m_pShareMemoryHandle != nullptr) {
        CloseHandle(m_pShareMemoryHandle);
        m_pShareMemoryHandle = nullptr;
    }

    //释放读缓冲区指针
    if(m_pReadBuf != nullptr){
        free(m_pReadBuf);
        m_pReadBuf = nullptr;
    }

    quitManager();
}

void ShareMemoryManager::startManager()
{
    if(m_pThread == nullptr){
        m_pThread = new QThread;
        this->moveToThread(m_pThread);
        m_pThread->start();
    }
}

void ShareMemoryManager::quitManager()
{
    if(m_pThread != nullptr){
        m_pThread->requestInterruption();
        m_pThread->quit();
        m_pThread->wait();
        m_pThread->deleteLater();
        m_pThread = nullptr;
    }
}

void ShareMemoryManager::initShareMemory(const int &shareMemorySize, const QString &shareMemoryKey)
{
    m_shareMemorySize = shareMemorySize;
    m_pShareMemoryHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_EXECUTE_READWRITE,0,shareMemorySize,shareMemoryKey.toStdWString().c_str());
    if (m_pShareMemoryHandle == NULL)
    {
        cout << "Could not create file mapping B object:" << GetLastError();
        return;
    }

    m_pShareMemoryBuffer = MapViewOfFile(m_pShareMemoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, shareMemorySize);
    if (m_pShareMemoryBuffer == NULL)
    {
        cout << "Could not map view of file B:" << GetLastError();
        CloseHandle(m_pShareMemoryHandle);
        return;
    }
}

void ShareMemoryManager::initSemaphore(const QString &readSemaphoreKey, const QString &writeSemaphoreKey)
{
    m_pReadSemaphoreForShareMem = CreateSemaphore(NULL, 0, 1, readSemaphoreKey.toStdWString().c_str());
    if (m_pReadSemaphoreForShareMem == NULL)
    {
        cout << "CreateSemaphore readSemName error: %d" << GetLastError();
        return;
    }

    m_pWriteSemaphoreForShareMem = CreateSemaphore(NULL, 0, 1, writeSemaphoreKey.toStdWString().c_str());
    if (m_pWriteSemaphoreForShareMem == NULL)
    {
        cout << "CreateSemaphore writeSemName error: %d" << GetLastError();
        return;
    }
}

void ShareMemoryManager::slot_writeMessageToShareMemory(const QString &message)
{
    strcpy_s((char*)m_pShareMemoryBuffer,m_shareMemorySize,message.toStdString().c_str());
    
    //释放共享内存的可读信号,通知其它进程可以读取内容
    ReleaseSemaphore(m_pReadSemaphoreForShareMem,1,NULL);
    //阻塞等待其它进程释放共享内存的可读信号,然后写进程进行下一轮写操作
    WaitForSingleObject(m_pWriteSemaphoreForShareMem,INFINITE);
}

void ShareMemoryManager::slot_readMessageFromShareMemory()
{
    if(m_pReadBuf == nullptr){
        m_pReadBuf = (char*)malloc(m_shareMemorySize*sizeof(char));
    }
    memset(m_pReadBuf,0,m_shareMemorySize);

    //阻塞等待写进程释放共享内存的可读信号
    DWORD semRet = WaitForSingleObject(m_pReadSemaphoreForShareMem,INFINITE);
    if (semRet == WAIT_OBJECT_0) {
        strcpy_s(m_pReadBuf,m_shareMemorySize,(char*)m_pShareMemoryBuffer);
        sig_readMessageFromShareMemory(QString(m_pReadBuf));
        //释放共享内存的写信号,通知写进程进行写操作
        ReleaseSemaphore(m_pWriteSemaphoreForShareMem,1,NULL);
    }
}

A进程调用接口实现写操作

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "ShareMemoryManager.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void sig_sendMessage(const QString &data);

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    ShareMemoryManager *m_pSMM;
};

#endif // MAINWINDOW_H

源文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_pSMM = new ShareMemoryManager(250,"shareMemory","readSemaphore","writeSemaphore");
    connect(this,SIGNAL(sig_sendMessage(QString)),m_pSMM,SLOT(slot_writeMessageToShareMemory(QString)),Qt::ConnectionType::QueuedConnection);
}

MainWindow::~MainWindow()
{
    if(m_pSMM != nullptr){
        m_pSMM->deleteLater();
        m_pSMM = nullptr;
    }
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString data = ui->lineEdit->text();
    emit sig_sendMessage(data);
}

UI文件同单共享内存单信号量

B进程调用接口实现读操作

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "ShareMemoryManager.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void slot_readMessageToShow(QString message);   //显示从共享内存读取的数据

private:
    Ui::MainWindow *ui;

    ShareMemoryManager *m_pSMM;
};

#endif // MAINWINDOW_H

源文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

m_pSMM = new ShareMemoryManager(250,"shareMemory","readSemaphore","writeSemaphore");
    connect(ui->pushButton,SIGNAL(clicked()),m_pSMM,SLOT(slot_readMessageFromShareMemory()));
    connect(m_pSMM,SIGNAL(sig_readMessageFromShareMemory(QString)),this,SLOT(slot_readMessageToShow(QString)));
}

MainWindow::~MainWindow()
{
    if(m_pSMM != nullptr){
        m_pSMM->deleteLater();
        m_pSMM = nullptr;
    }
    delete ui;
}

void MainWindow::slot_readMessageToShow(QString message)
{
    ui->plainTextEdit->appendPlainText(message);
}

UI文件同单共享内存单信号量文章来源地址https://www.toymoban.com/news/detail-481822.html

四,双共享内存双信号量-进程间双向通信

到了这里,关于【C++】Windows下共享内存加信号量实现进程间同步通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【设计模式】C语言使用共享内存和信号量,完美实现生产者与消费者模式

    生产者和消费者模式适用于生产者和消费者之间存在数据交换的场景。在这种模式中,生产者负责生产数据并将其放入缓冲区,而消费者负责从缓冲区中取出数据并进行处理。这种模式的优点是可以实现生产者和消费者之间的解耦,使得它们可以独立地进行操作,从而提高了

    2024年02月03日
    浏览(28)
  • 【linux】进行间通信——共享内存+消息队列+信号量

    进程间通信方式目前我们已经学了匿名管道,命名管道。让两个独立的进程通信,前提是看到同一份资源。匿名管道适用于血缘关系的进程,一个打开写端一个打开读端实现的。命名管道适用于完全独立的进程,打开同一份文件实现的。 接下来我们看看剩下的实现进程间通信

    2024年02月05日
    浏览(35)
  • 【Linux】System V 共享内存、消息队列、信号量

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 System V 共享内存是一种进程间通信的机制,它允许多个进程 共享一块物理内存区域 (称为“段”)。System V 共享内存的优点是效率高,因为进程之间不需要复制数据;缺点是 需要进程之间进行同步,以避免数据的不一致性 。 共

    2024年02月04日
    浏览(39)
  • 二、操作系统进程管理(10)——用信号量机制实现进程互斥、同步、前驱关系

        (1)分析并发进程的关键活动,划定临界区。(如对临界区资源打印机的访问就应放在临界区)     (2)设置互斥信号量mutex,初值为1。     (3)在临界区之前执行P(mutex)。      //即使用资源前先申请(P操作)     (4)在临界区之后执行V(mutex)。     (5)对不

    2023年04月08日
    浏览(30)
  • 【Linux】进程间通信 -- 信号量

    信号量是什么? 本质是一个计数器,通常用来表示公共资源中,资源数量多少的问题 公共资源:能被多个进程同时可以访问的资源 访问没有保护的公共资源:数据不一致问题(比如我想写abc123,但是我123还没有写入,就读取了abc,可能数据分开会导致数据无意义) 为什么要

    2024年02月16日
    浏览(32)
  • linux进程间通信(信号量)

    信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即 P(信号变量))和发 送(即 V(信号变量))信息操作。最简单的信号量是只能取 0 和 1 的变量,这也是信号量最常见的一种形式, 叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号

    2024年02月07日
    浏览(25)
  • Linux进程间通信【消息队列、信号量】

    ✨个人主页: 北 海 🎉所属专栏: Linux学习之旅 🎃操作环境: CentOS 7.6 阿里云远程服务器 在 System V 通信标准中,还有一种通信方式: 消息队列 ,以及一种实现互斥的工具: 信号量 ;随着时代的发展,这些陈旧的标准都已经较少使用了,但作为 IPC 中的经典知识,我们可

    2024年02月08日
    浏览(29)
  • 【Linux】进程间通信——System V信号量

    目录 写在前面的话 一些概念的理解 信号量的引入 信号量的概念及使用            System V信号量是一种较低级的IPC机制 ,使用的时候需要手动进行操作和同步。在现代操作系统中,更常用的是 POSIX信号量 (通过 sem_* 系列的函数进行操作)或更高级的同步原语(如互斥锁

    2024年02月11日
    浏览(35)
  • 【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念

             访问资源在安全的前提下,具有一定的顺序性,就叫做同步 。在多道程序系统中,由于资源有限,进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突,保证进程或线程之间能够按照既定的顺序访问共享资源。同步机制有助于避免竞态条件和死锁(

    2024年04月25日
    浏览(25)
  • 用信号量机制解决读者-写者问题C语言实现

    文章目录 介绍 一、什么是进程同步,进程互斥 二、读者-写者问题概述 1.概念图 2.实例代码 总结 通过实验模拟读者和写者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。具体如下:   1)掌握基本的同步互斥算法,理解读者和写者模型

    2024年02月02日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包