您当前的位置: 首页 >  c++

插件开发

暂无认证

  • 0浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C++ 信号处理-共享内存-服务端-客户端-Event

插件开发 发布时间:2022-06-16 08:00:00 ,浏览量:0

文章目录
    • 1.事件对象常用API
      • 1.1.CreateEvent
      • 1.2.SetEvent/ResetEvent
      • 1.3.WaitForSingleObject
      • 1.4.简单范例
    • 2.共享内存常用API
      • 2.1.CreateFileMapping
      • 2.2.MapViewOfFile
    • 3.综合范例
    • 4.作者答疑
  在进程间通信时,必然会面临数据交互问题,本文简述如何就进程间的通信做出简要解答。

1.事件对象常用API 1.1.CreateEvent

  CreateEvent是一个WindowsAPI函数。它用来创建或打开一个命名的或无名的事件对象。如果想为对象指定一个访问掩码,应当使用CreateEventEx函数。

HANDLE CreateEvent(
    LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
    BOOL bManualReset,// 复位方式
    BOOL bInitialState,// 初始状态
    LPCTSTR lpName // 对象名称
);

  lpEventAttributes: 一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。   bManualReset: 指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当一个线程等待到事件信号后系统会自动将事件状态复原为无信号状态。   bInitialState: 指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。   lpName: 指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。如果lpName为NULL,将创建一个无名的事件对象。如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。

1.2.SetEvent/ResetEvent

  SetEvent/ResetEvent分别将EVENT置为这两种状态分别是发信号与不发信号。

//将指定的事件对象设置为信号状态。
BOOL SetEvent(
	[in] HANDLE hEvent
);//其中hEvent表示句柄,返回值:如果操作成功,则返回非零值,否则为0。
BOOL ResetEvent(
  [in] HANDLE hEvent
);
//[in] hEvent 事件对象的句柄。CreateEvent或 OpenEvent 函数返回此句柄。

//打开现有的命名事件对象。
HANDLE OpenEventA(
  [in] DWORD  dwDesiredAccess,
  [in] BOOL   bInheritHandle,
  [in] LPCSTR lpName
);
/*
[in] dwDesiredAccess
对事件对象的访问。如果指定对象的安全描述符不允许调用进程请求访问,则函数失败。有关访问权限的列表,请参阅 同步对象安全性和访问权限。
[in] bInheritHandle
如果此值为TRUE,则由该进程创建的进程将继承句柄。否则,进程不会继承此句柄。
[in] lpName
要打开的事件的名称。名称比较区分大小写。
返回值
如果函数成功,则返回值是事件对象的句柄。
如果函数失败,则返回值为NULL。要获取扩展的错误信息,请调用 GetLastError。
*/
1.3.WaitForSingleObject

  WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。如果时间设置为INFINITE,直到有信号才返回。

DWORD WaitForSingleObject(
    HANDLE hHandle,
    DWORD dwMilliseconds 
);

  执行成功,返回值指示出引发函数返回的事件。它可能为以下值:   WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。   WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态。   WAIT_TIMEOUT 0x00000102:等待超时。   WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码。

1.4.简单范例
//创建一个需要手工将事件的状态复原到无信号状态,初始为无信号的事件。
HANDLE hOver = CreateEvent(NULL,
		TRUE,
		FALSE,
		"hOver");

//阻塞线程直到信号出现
WaitForSingleObject(hOver,INFINITE);

//其它线程调用发送信号
SetEvent(hOver);

//下次使用阻塞时需要手动重置为无信号
ResetEvent(hOver);
2.共享内存常用API 2.1.CreateFileMapping

  CreateFileMapping函数用于创建一个文件映射内核对象。

CreateFileMappingA(
    _In_     HANDLE hFile,
    _In_opt_ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
    _In_     DWORD flProtect,
    _In_     DWORD dwMaximumSizeHigh,
    _In_     DWORD dwMaximumSizeLow,
    _In_opt_ LPCSTR lpName
    );

  hFile: Long,指定欲在其中创建映射的一个文件句柄。0xFFFFFFFF(-1,即INVALID_HANDLE_VALUE)表示在页面文件中创建一个可共享的文件映射。   lpFileMappigAttributes: SECURITY_ATTRIBUTES,它指明返回的句柄是否可以被子进程所继承,指定一个安全对象,在创建文件映射时使用。如果为NULL(用ByVal As Long传递零),表示使用默认安全对象。   flProtect: Long,下述常数之一:PAGE_READONLY 以只读方式打开映射;PAGE_READWRITE 以可读、可写方式打开映射;PAGE_WRITECOPY 为写操作留下备份,可组合使用下述一个或多个常数:SEC_COMMIT 为文件映射一个小节中的所有页分配内存。SEC_IMAGE 文件是个可执行文件;SEC_RESERVE 为没有分配实际内存的一个小节保留虚拟内存空间。

  dwMaximumSizeHigh: Long,文件映射的最大长度的高32位。   dwMaximumSizeLow: Long,文件映射的最大长度的低32位。如这个参数和dwMaximumSizeHigh都是零,就用磁盘文件的实际长度。   lpName: String,指定文件映射对象的名字。如存在这个名字的一个映射,函数就会打开它。用vbNullString可以创建一个无名的文件映射。   调用CreateFileMapping的时候可能会出现的GetLastError的相应错误:ERROR_FILE_INVALID (错误_文件_无效)如果企图创建一个零长度的文件映射;ERROR_INVALID_HANDLE(错误_无效_处理) 内存空间的命名和现有的内存映射,互斥量,信号量,临界区有同名;ERROR_ALREADY_EXISTS (错误或已经存在)表示内存空间命名已经存在;在调用CreateFileMapping()时,可以用GetLastError()来检查其返回的错误信息。如果返回值为ERROR_ALREADY_EXISTS,则表示内存映射对象指定名字已经存在。有关其他返回值的意义见MSDN的详细说明。

2.2.MapViewOfFile

  将一个文件映射对象映射到当前应用程序的地址空间。MapViewOfFileEx允许我们指定一个基本地址来进行映射。

LPVOID WINAPI MapViewOfFile(
      __in HANDLE hFileMappingObject,
      __in DWORD dwDesiredAccess,
      __in DWORD dwFileOffsetHigh,
      __in DWORD dwFileOffsetLow,
      __in SIZE_T dwNumberOfBytesToMap
      );
LPVOID WINAPI MapViewOfFileEx(
      __in HANDLE hFileMappingObject,
      __in DWORD dwDesiredAccess,
      __in DWORD dwFileOffsetHigh,
      __in DWORD dwFileOffsetLow,
      __in SIZE_T dwNumberOfBytesToMap,
      __in LPVOID lpBaseAddress
      );

参数1: hFileMappingObject 为CreateFileMapping()或OpenFileMapping()返回的文件映像对象句柄。 参数2: dwDesiredAccess 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。 可取以下值:FILE_MAP_ALL_ACCESS 等价于CreateFileMapping的 FILE_MAP_WRITE|FILE_MAP_READ. 文件映射对象被创建时必须指定PAGE_READWRITE 选项。FILE_MAP_COPY 可以读取和写入文件.写入操作会导致系统为该页面创建一份副本.在调用CreateFileMapping时必须传入PAGE_WRITECOPY保护属性。FILE_MAP_EXECUTE 可以将文件中的数据作为代码来执行.在调用CreateFileMapping时可以传入PAGE_EXECUTE_READWRITE或PAGE_EXECUTE_READ保护属性。FILE_MAP_READ 可以读取文件.在调用CreateFileMapping时可以传入PAGE_READONLY或PAGE_READWRITE保护属性。FILE_MAP_WRITE 可以读取和写入文件.在调用CreateFileMapping时必须传入PAGE_READWRITE保护属性。 参数3: dwFileOffsetHigh 表示文件映射起始偏移的高32位。 参数4: dwFileOffsetLow 表示文件映射起始偏移的低32位。(64KB对齐不是必须的) 参数5: dwNumberOfBytes 指定映射文件的字节数。

3.综合范例

ShareDataServer.h

#pragma once
#include 

class ShareDataServer
{
public:
	ShareDataServer();
	~ShareDataServer();

	bool init();
	bool run();
	bool func();
	bool dataopt(char* data);

public:
	HANDLE hMutex;
	HANDLE hFileMapping;
	LPVOID lpShareMemory;
	HANDLE hServerProcessOver;
	HANDLE hClientWriteOver;
	HANDLE hServerProcessStart;
	HANDLE hClientWriteStart;
};

ShareDataServer.cpp

#include "ShareDataServer.h"
#include 
#include 

#define SHARE_DATA_WIDTH 1024
#define SHARE_DATA_HEIGHT 1024

ShareDataServer::ShareDataServer()
{
	hMutex = NULL;
	hFileMapping = NULL;
	lpShareMemory = NULL;
	hServerProcessOver = NULL;
	hClientWriteOver = NULL;
	hServerProcessStart;
	hClientWriteStart;
}

ShareDataServer::~ShareDataServer()
{
	if (NULL != hServerProcessStart)	CloseHandle(hServerProcessStart);
	if (NULL != hClientWriteStart)	CloseHandle(hClientWriteStart);
	if (NULL != hServerProcessOver)	CloseHandle(hServerProcessOver);
	if (NULL != hClientWriteOver)	CloseHandle(hClientWriteOver);
	
	if (NULL != hMutex)				ReleaseMutex(hMutex);
}

bool ShareDataServer::init(){
	//read and write data
	hServerProcessOver = CreateEvent(NULL,
		TRUE,
		FALSE,
		"hServerProcessOver");
	hClientWriteOver = CreateEvent(NULL,
		TRUE,
		FALSE,
		"hClientWriteOver");
	if (NULL == hServerProcessOver ||
		NULL == hClientWriteOver)
	{
		std::cout             
关注
打赏
1665481431
查看更多评论
0.0531s