65.9K
CodeProject 正在变化。 阅读更多。
Home

终极共享内存:一个灵活的进程间内存共享类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (22投票s)

2014年11月1日

CPOL

3分钟阅读

viewsIcon

59867

downloadIcon

1285

一个灵活的内存共享类,可在进程和线程之间共享,并支持锁定

引言

这是一个用于在 Windows 中跨线程或进程共享内存的模板类。它提供锁定机制、通知等等!

Using the Code

类的实例化

// usm(const wchar_t* string_id = 0,bool Init = false,size_t csz = 1048576,DWORD MaxTh = 100)
usm<char> sm(L"{4BF41A4E-ACF9-4E1D-A479-14DE9FF83BC2}",false,1000,100);
  • string_id 是一个 string,它唯一地标识此共享内存的内核对象。所有使用相同 string_idusm 实例都在访问相同的内存。建议使用 CLSID 值以避免与其他使用 usm 的应用程序可能发生的冲突。
    如果您传递 0,则对象保持未初始化状态。要初始化该对象,您必须调用 CreateInit,它采用与构造函数相同的参数。
  • Init 指定对象的初始化是否必须包含在构造函数中。如果此值为 true 并且发生错误,则构造函数将引发异常。
  • csz 指定要分配的项目数。在上面的示例中,总内存分配为 csz*sizeof(char)
  • MaxTh 是将访问共享内存的最大线程数。在共享相同 string_id 的类的任何实例中,此数字必须相同,否则会发生内存损坏。

该库分配内存来存储每个线程的事件,因此在使用相同内存(即,相同的 string_id)的类的所有实例中,MaxTh 必须相同。

类的初始化

//  int Initialize();

此函数创建同步所需的内核对象句柄。调用 End() 会销毁这些句柄。 Initialize() 成功时返回 1,出错时返回 -1。如果 Initialize() 失败,则 End() 会清理所有剩余句柄。该类的析构函数也调用 End()

如果另一个线程正在写入共享内存,则此函数会等到写入完成为止。

读取共享内存

// unsigned long long ReadData(T* b,size_t sz,size_t offset = 0,bool FailIfNotReady = false);

此函数(在内部调用 BeginRead()EndRead())执行以下操作

  • 如果 FailfNotReadytrue 并且任何写入线程尚未完成写入,则该函数立即返回 -1。如果 FailIfNotReadyfalse,则该函数会等到任何写入线程完成写入为止。
  • 将调用线程的当前状态标记为正在读取。这会强制任何写入线程等待直到读取完成为止。
  • 读取数据。
  • 将调用线程的状态标记为未读取。这允许任何写入线程恢复(只要没有更多的读取线程)。
  • 返回与 sz 相同的值。

写入共享内存

// unsigned long long WriteData(const T* b,size_t sz,size_t offset = 0,bool FailIfNotReady = false);

此函数(在内部调用 BeginWrite()EndWrite())执行以下操作

  • 如果 FailfNotReadytrue 并且任何其他线程正在写入或读取,则该函数立即返回 -1。如果 FailIfNotReadyfalse,则该函数会等到任何其他写入或读取线程完成为止。
  • 将调用线程的当前状态标记为正在写入。这会强制任何其他线程(读取或写入)等待直到写入完成为止。这也会强制任何使用 Initialize() 初始化对象的线程等待。
  • 写入数据。
  • 将调用线程的状态标记为未写入。这允许任何其他写入或读取线程恢复。该函数还会设置一个事件,指示内存已被写入。
  • 返回与 sz 相同的值。

如果您需要指向数据的指针,则可以调用 BeginRead()(必须随后调用 EndRead())和 BeginWrite()(必须随后调用 EndWrite())。

const T* BeginRead(bool FailOnNotReady = false);
void EndRead();
T* BeginWrite(bool FailOnNotReady = false);
void EndWrite();

Notifications

// DWORD NotifyOnRead(bool Wait);
// DWORD NotifyWrite(bool Wait);
  • 如果您调用 NotifyOnRead,并且此函数的 Wait == false,则该函数返回
    • -1 如果函数失败
    • -2 如果没有其他已注册的线程
    • WAIT_TIMEOUT 如果任何线程仍在读取
    • WAIT_OBJECT_0 或更大的值,如果任何读取线程已完成
  • 如果您使用 Wait == true 调用 NotifyOnRead,则返回值相同,只是如果所有线程仍在读取,则该函数不会返回。

如果线程刚刚完成写入,则 NotifyOnWrite 返回 WAIT_OBJECT_0(请注意,此事件是自动重置的)。如果线程未写入或仍在写入,则 NotifyOnWrite 要么返回 WAIT_TIMEOUT(如果您使用 Wait == false 调用它),要么等待直到线程完成写入。

希望这个类对您有帮助。它对我来说已经非常有用了。
祝您好运!

历史

  • 2014年11月2日 - 增加了稍后初始化的能力,并添加了复制构造函数和运算符 =,以及增加了读/写函数的偏移量
  • 2014年11月1日 - 首次发布
© . All rights reserved.