使用临界段实现优化的进程间同步对象-原理和实现

Java中进程间通信(IPC)的7种主要方式及原理剖析 在Java开发中,进程间通信(Inter-Process Communication, IPC)是实现不同Java虚拟机(JVM)或本地进程间数据交换的关键技术。本文将介绍7种常见的IPC方式,结合时序图和代码示例,深入剖析其原理与适用场景。 阅读详情

1.概述:

在多进程的环境里,需要对线程进行同步.常用的同步对象有临界段(Critical Section),互斥量(Mutex),信号量(Semaphore),事件(Event)等,除了临界段,都是内核对象。

在同步技术中,临界段(Critical Section)是最容易掌握的,而且,和通过等待和释放内核态互斥对象实现同步的方式相比,临界段的速度明显胜出.但是临界段有一个缺陷,WIN32文档已经说明了临界段是不能跨进程的,就是说临界段不能用在多进程间的线程同步,只能用于单个进程内部的线程同步.

因为临界段只是一个很简单的数据结构体,在别的进程的进程空间里是无效的。就算是把它放到一个可以多进程共享的内存映象文件里,也还是无法工作.

有甚么方法可以跨进程的实现线程的高速同步吗?

2.原理和实现

2.1为什么临界段快? 是“真的”快吗?

确实,临界段要比其他的核心态同步对象要快,因为EnterCriticalSection和LeaveCriticalSection这两个函数从InterLockedXXX系列函数中得到不少好处(下面的代码演示了临界段是如何使用InterLockedXXX函数的)。InterLockedXXX系列函数完全运行于用户态空间,根本不需要从用户态到核心态

之间的切换。所以,进入和离开一个临界段一般只需要10个左右的CPU执行指令。而当调用WaitForSingleObject之流的函数时,因为使用了内核对象,线程被强制的在用户态和核心态之间变换。在x86处理器上,这种变换一般需要600个CPU指令。看到这里面的巨大差距了把。

话说回来,临界段是不是真正的“快”?实际上,临界段只在共享资源没有冲突的时候是快的。当一个线程试图进入正在被另外一个线程拥有的临界段,即发生竞争冲突时,临界段还是等价于一个event核心态对象,一样的需要耗时约600个CPU指令。事实上,因为这样的竞争情况相对一般的运行情况来说是很少的(除非人为),所以在大部分的时间里(没有竞争冲突的时候),临界段的使用根本不牵涉内核同步,所以是高速的,只需要10个CPU的指令。(bear说:明白了吧,纯属玩概率,Ms的小花招)

2.3进程边界怎么办?

“临界段等价于一个event核心态对象”是什么意思?

看看临界段结构的定义先

typedef struct _RTL_CRITICAL_SECTION {

PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

//

// The following three fields control entering and exiting the critical

// section for the resource

//

LONG LockCount;

LONG RecursionCount;

HANDLE OwningThread; // from the thread's ClientId->UniqueThread

HANDLE LockSemaphore;

DWORD SpinCount;

} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

#typedef RTL_CRITICAL_SECTION CRITICL_SECTION

在CRITICAL_SECTION 数据结构里,有一个Event内核对象的句柄(那个undocument的结构体成员LockSemaphore,包含的实际是一个event的句柄, 而不是一个信号量semaphore)。正如我们所知,内核对象是系统全局的,但是该句柄是进程所有的,而不是系统全局的。所以,就算把一个临界段结构直接放到共享的内存映象里,临界段也无法起作用,因为LockSemaphore里句柄值只对一个进程有效,对于别的进程是没有意义的。 在一般的进程同步中,进程要使用一个存在于别的进程里的Event 对象,必须调用OpenEvent或CreaetEvent函数来得到进程可以使用的句柄值。

CRITICAL_SECTION结构里其他的变量是临界段工作所依赖的元素,Ms也“警告”程序员不要自己改动该结构体里变量的值。是怎么实现的呢?看下一步.

2.4 COptex,优化的同步对象类

Jeffrey Richter曾经写过一个自己的临界段,现在,他把他的临界段改良了一下,把它封装成一个COptex类。成员函数TryEnter拥有NT4里介绍的函数TryEnterCriticalSection的功能,这个函数尝试进入临界段,如果失败立刻返回,不会挂起线程,并且支持Spin计数.这个功能在NT4/SP3中被InitializeCriticalSectionAndSpinCount 和SetCriticalSectionSpinCount实现。Spin计数在多处理器系统和高竞争冲突情况下是很有用的,在进入WaitForXXX核心态之前,临界段根据设定的Spin计数进行多次TryEnterCtriticalSection,然后才进行堵塞。想一下,TryEnterCriticalSection才使用10个左右的周期,如果在Spin计数消耗完之前,冲突消失,临界段对象是空闲的,那么再用10个CPU周期就可以在用户态进入临界段了,不用切换到核心态.

(bear说:为了避免这个"核心态",Ms自己也是费劲脑汁呀.看出来了吧,优化的原则:在需要的时候才进入核心态。否则,在用户态进行同步)

以下是COptex代码。原代码下载

Figure 2: COptex

Optex.h

/******************************************************************************

Module name: Optex.h

Written by: Jeffrey Richter

Purpose: Defines the COptex (optimized mutex) synchronization object

******************************************************************************/

#pragma once

///////////////////////////////////////////////////////////////////////////////

class COptex {

public:

COptex(LPCSTR pszName, DWORD dwSpinCount = 4000);

COptex(LPCWSTR pszName, DWORD dwSpinCount = 4000);

~COptex();

void SetSpinCount(DWORD dwSpinCount);

void Enter();

BOOL TryEnter();

void Leave();

private:

typedef struct {

DWORD m_dwSpinCount;

long m_lLockCount;

DWORD m_dwThreadId;

long m_lRecurseCount;

} SHAREDINFO, *PSHAREDINFO;

BOOL m_fUniprocessorHost;

HANDLE m_hevt;

HANDLE m_hfm;

PSHAREDINFO m_pSharedInfo;

private:

BOOL CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount);

};

///////////////////////////////////////////////////////////////////////////////

inline COptex::COptex(LPCSTR pszName, DWORD dwSpinCount) {

CommonConstructor((PVOID) pszName, FALSE, dwSpinCount);

}

///////////////////////////////////////////////////////////////////////////////

inline COptex::COptex(LPCWSTR pszName, DWORD dwSpinCount) {

CommonConstructor((PVOID) pszName, TRUE, dwSpinCount);

}

Optex.cpp

/******************************************************************************

Module name: Optex.cpp

Written by: Jeffrey Richter

Purpose: Implements the COptex (optimized mutex) synchronization object

******************************************************************************/

#include <windows.h>

#include "Optex.h"

///////////////////////////////////////////////////////////////////////////////

BOOL COptex::CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount)

{

m_hevt = m_hfm = NULL;

m_pSharedInfo = NULL;

SYSTEM_INFO sinf;

GetSystemInfo(&sinf);

m_fUniprocessorHost = (sinf.dwNumberOfProcessors == 1);

char szNameA[100];

if (fUnicode) { // Convert Unicode name to ANSI

wsprintfA(szNameA, "%S", pszName);

pszName = (PVOID) szNameA;

}

char sz[100];

wsprintfA(sz, "JMR_Optex_Event_%s", pszName);

m_hevt = CreateEventA(NULL, FALSE, FALSE, sz);

if (m_hevt != NULL) {

wsprintfA(sz, "JMR_Optex_MMF_%s", pszName);

m_hfm = CreateFileMappingA(NULL, NULL, PAGE_READWRITE, 0, sizeof(*m_pSharedInfo), sz);

if (m_hfm != NULL) {

m_pSharedInfo = (PSHAREDINFO) MapViewOfFile(m_hfm, FILE_MAP_WRITE,

0, 0, 0);

// Note: SHAREDINFO's m_lLockCount, m_dwThreadId, and m_lRecurseCount

// members need to be initialized to 0. Fortunately, a new pagefile

// MMF sets all of its data to 0 when created. This saves us from

// some thread synchronization work.

if (m_pSharedInfo != NULL)

SetSpinCount(dwSpinCount);

}

}

return((m_hevt != NULL) && (m_hfm != NULL) && (m_pSharedInfo != NULL));

}

///////////////////////////////////////////////////////////////////////////////

COptex::~COptex() {

#ifdef _DEBUG

if (m_pSharedInfo->m_dwThreadId != 0) DebugBreak();

#endif

UnmapViewOfFile(m_pSharedInfo);

CloseHandle(m_hfm);

CloseHandle(m_hevt);

}

///////////////////////////////////////////////////////////////////////////////

void COptex::SetSpinCount(DWORD dwSpinCount) {

if (!m_fUniprocessorHost)

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwSpinCount, dwSpinCount);

}

///////////////////////////////////////////////////////////////////////////////

void COptex::Enter() {

// Spin, trying to get the Optex

if (TryEnter()) return;

DWORD dwThreadId = GetCurrentThreadId(); // The calling thread's ID

if (InterlockedIncrement(&m_pSharedInfo->m_lLockCount) == 1) {

// Optex is unowned, let this thread own it once

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, dwThreadId);

m_pSharedInfo->m_lRecurseCount = 1;

} else {

// Optex is owned by a thread

if (m_pSharedInfo->m_dwThreadId == dwThreadId) {

// Optex is owned by this thread, own it again

m_pSharedInfo->m_lRecurseCount++;

} else {

// Optex is owned by another thread

// Wait for the Owning thread to release the Optex

WaitForSingleObject(m_hevt, INFINITE);

// We got ownership of the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId,

dwThreadId); // We own it now

m_pSharedInfo->m_lRecurseCount = 1; // We own it once

}

}

}

///////////////////////////////////////////////////////////////////////////////

 

BOOL COptex::TryEnter() {

DWORD dwThreadId = GetCurrentThreadId(); // The calling thread's ID

// If the lock count is zero, the Optex is unowned and

// this thread can become the owner of it now.

BOOL fThisThreadOwnsTheOptex = FALSE;

DWORD dwSpinCount = m_pSharedInfo->m_dwSpinCount;

do {

fThisThreadOwnsTheOptex = (0 == (DWORD)

InterlockedCompareExchange((PVOID*) &m_pSharedInfo->m_lLockCount,

(PVOID) 1, (PVOID) 0));

if (fThisThreadOwnsTheOptex) {

// We now own the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId,

dwThreadId); // We own it

m_pSharedInfo->m_lRecurseCount = 1; // We own it once

} else {

// Some thread owns the Optex

if (m_pSharedInfo->m_dwThreadId == dwThreadId) {

// We already own the Optex

InterlockedIncrement(&m_pSharedInfo->m_lLockCount);

m_pSharedInfo->m_lRecurseCount++; // We own it again

fThisThreadOwnsTheOptex = TRUE; // Return that we own the Optex

}

}

} while (!fThisThreadOwnsTheOptex && (dwSpinCount-- > 0));

// Return whether or not this thread owns the Optex

return(fThisThreadOwnsTheOptex);

}

 

///////////////////////////////////////////////////////////////////////////////

 

void COptex::Leave() {

#ifdef _DEBUG

if (m_pSharedInfo->m_dwThreadId != GetCurrentThreadId())

DebugBreak();

#endif

if (--m_pSharedInfo->m_lRecurseCount > 0) {

// We still own the Optex

InterlockedDecrement(&m_pSharedInfo->m_lLockCount);

} else {

// We don't own the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 0);

if (InterlockedDecrement(&m_pSharedInfo->m_lLockCount) > 0) {

// Other threads are waiting, wake one of them

SetEvent(m_hevt);

}

}

}

 

///////////////////////////////// End of File /////////////////////////////////

使用这个COptex是很简单的事情,只要构造用下面这两种构造函数一个C++类的实例即可.

构造函数

COptex(LPCSTR pszName, DWORD dwSpinCount = 4000);

COptex(LPCWSTR pszName, DWORD dwSpinCount = 4000);

他们都调用了

BOOL CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount);

构造一个COptex对象必须给它一个字符串型的名字,在突破进程边界的时候这是必须的,只有这个名字能提供共享访问.构造函数支持ANSI或Unicode的名字。

当另外一个进程使用相同的名字构造一个COptex对象,构造函数如何发现已经存在的COptex对象?在CommonConstructor代码中用CreateEvent尝试创建一个命名Event对象,如果这个名字的Event对象已经存在,那么,得到该对象的句柄,并且GetLastError可以得到ERROR_ALREADY_EXISTS.如果不存在则创建一个.如果创建失败,则得到的句柄为NULL.

同样的,可以得到一个共享的内存映象文件的句柄.

构造成功后,在需要同步时,根据情况简单的执行相应的进程间同步操作。构造函数的第二个参数用来指定Spin计数,默认是4000(这是操作系统序列化堆Heap的函数所使用的数量.操作系统在分配和释放内存的时候,要序列化进程的堆,这时也要用到临界段)

COptex类的其他函数和Win32函数是一一对应的.熟悉同步对象的程序员应该很容易理解.

COptex是如何工作的呢?实际上,一个COptex包含两个数据块(Data blocks):一个本地的,私有的;另一个是全局的,共享的.一个COptex对象构造之后,本地数据块包含了COptex的成员变量:m_hevt变量初始化为一个命名事件对象句柄;m_hfm变量初始化为一个内存映象文件对象句柄.既然这些句柄代表的对象是命名的,那么,他们可以在进程间共享。注意,是"对象"可以共享,而不是"对象的句柄".每个进程内的COptex对象都必须保持这些句柄在本进程内的值.

m_pShareInf成员指向一个内存映象文件,全局数据块在这个内存映象文件里,以指定的共享名存在. SHAREDINFO结构是内存映象数据的组织方式,该结构在COptex类里定义,和CRITCIAL_SECTION的结构非常相似.

typedef struct {

DWORD m_dwSpinCount;

long m_lLockCount;

DWORD m_dwThreadId;

long m_lRecurseCount;report-2001-03-07.htm

} SHAREDINFO, *PSHAREDINFO;

m_dwSpinCount : spin计数

m_lLockCount : 锁定计数

m_dwThreadID : 拥有该临界段的线程ID

m_lRecurseCount:本线程拥有该临界段的计数

好了,仔细看看代码吧,大师风范呀.注意一下在进行同步时,关于是否同一线程,关于LockCount的值的一系列的判断,以及InterLockedXXX系列函数的使用,具体用法查MSDN.

bear最喜欢这样的代码了,简单明了,思路清晰,原理超值,看完了只想大喝一声"又学一招,爽!"

bear也写累了 ,收工:).

2001.3.2

随意转载,只要不去掉Jeffrey的名字,还有bear的:D

翻译有错,请找vcbear@sina.com或留言,不懂Win32编程看下面:

Have a question about programming in Win32? Contact Jeffrey Richter at http://www.jeffreyrichter.com/

From the January 1998 issue of Microsoft Systems Journal.

使用WM_COPYDATA实现Windows进程间数据传递 Windows操作系统中,进程间通信(Inter-Process Communication,IPC)是实现不同进程间数据交换与功能协作的重要机制。IPC技术的多样性,包括管道、套接字、内存映射文件以及WM_COPYDATA等,为开发者提供了灵活的选择以满足不同的应用场景需求。本章旨在对Windows IPC进行基础概述,为后续章节中深入探讨WM_COPYDATA消息机制提供必要的背景知识。在Windows操作系统中,进程间通信(IPC)是一个复杂但非常重要的概念。 阅读详情

相关推荐

用VASPKIT+Quantum Espresso高效绘制能带图:从K点路径生成到可视化全流程

本文详细介绍了如何整合VASPKIT与Quantum Espresso(QE)软件,构建一套高效的能带计算与可视化工作流。通过VASPKIT自动化生成高对称K点路径,结合QE完成自洽与非自洽计算,并利用gnuplot绘制发表级能带图。该流程极大提升了材料电子结构研究的效率与可重复性,是进行DFT能带计算的实用指南。

weixin_29294975的博客 163

使用临界段原理实现优化的进程间同步对象-原理和实现

     使用临界段原理实现优化的进程间同步对象-原理和实现by Jeffrey.Richter vcbear 热情讲解实现自己的同步对象?需要吗?不需要吗?...只是跟你研究一下而已.算了吧我只是个爱灌水的家伙,很久没有写代码了,闲来无事,灌灌水还不行吗? 1.概述:在多进程的环境里,需要对线程进行同步.常用的同步对象有临界段(Crit

vcbear的专栏 1576

Cadence IC618/Spectre231安装避坑指南:详解License配置、环境变量隔离与依赖检查

本文详细介绍了Cadence IC618/Spectre231的安装与配置避坑指南,包括许可证系统精妙控制、环境隔离模块化实践、依赖管理进阶技巧以及长期维护的黄金法则。通过实战案例和解决方案,帮助工程师构建稳定可靠的EDA工作环境,提升芯片设计效率。

weixin_28683065的博客 460

操作系统 进程管理(三)——进程同步方法简述

目录 进程同步的基本概念 1)两种形式的制约关系 2)Critical section(临界区) 3)Mutual exclusion(互斥) 4)Dead lock(死锁) 5)Starvation(饥饿) 6)面包问题(锁的概念) 同步机制原则 实现进程互斥的方法 方法一 基于软件的解决方案 算法一 x 算法二 x 算法三 x 算法四——Peterson算法 1981 √ 算法五——Backery算法作为补充 方法二 禁用硬件中断 (一)锁方法 TS互斥 (二)交换.

LarsGyonX的博客 3271

硬件开发流程

研发流程在一个有一定规模的企业中起到了非常重要的作用,也是一个产品或者项目成功量产出货依赖的平台体系,作为工程师如果想要走的更远,就必须了解流程体系,了解如何对产品的开发质量进行更好的管控。...

weixin_44126796的博客 8379

yolov5部署之七步完成tensorRT模型推理加速

目录前言step 1. 下载yolov5源码以及tensorrtx源码,并将yolov5s.pt转为.wts模型step 2. 确定并下载自己准备使用的CUDA版本。step 3. 根据自己的CUDA版本下载对应版本的cuDNN以及TensorRTstep 4. 根据自己使用的VS版本下载对应版本的OpenCVstep 5. 安装CUDAstep 6. 安装cuDNN、TensorRT以及验证TensorRT是否安装成功 前言     前段时间研究了Pytorch的环境配置,之后便从github上下载了yo

Christo的博客 4万+

Critical Section 线程同步 (C/C++ Windows Platform SDK 实现)

Mutex和Event是系统内核对象,好处是他们是跨进程的,可以用作进程间的线程同步。缺点也很明显,就是他们的速度较慢。Critical Section则是用户对象,速度快,但是不能设置超时时间,一不小心会造成死锁。(记得操作系统课本上的哲学家饿死问题吗,幸好哲学家不搞程序,要不然非气吐血不可)。。。一个很简单的Critical Section示例:// Coding by nyzhl

&*焰火*&天堂 2385

海上AI导航系统:技术架构与行业应用解析

计算机视觉与强化学习技术在海上导航系统中的应用正逐步改变传统航运业。通过多模态传感器融合技术,现代AI导航系统能够实现高精度的物体识别与实时路径规划,有效解决能见度依赖、决策延迟等核心痛点。以Orca AI的SeaPod系统为例,其结合了NVIDIA GeForce RTX 4070的边缘计算能力与多光谱协同识别技术,在恶劣环境下仍能保持稳定性能。这类系统不仅提升了航行安全性,还通过优化航线显著降低燃油消耗,在东京湾、马六甲海峡等繁忙水域展现出巨大价值。随着毫米波雷达融合方案的测试推进,未来海上导航将突破极

weixin_33597080的博客 354

进程的同步和互斥

当一次需要N个单位时,便要进行N次wait(S)操作,这显然是低效的,甚至会增加死锁的概率。此外,在有些情况下,为确保系统的安全性,当所申请的资源数量低于某一下限值时,还必须进行管制,不予以分配。因此,当进程申请某类临界资源时,在每次分配之前,都必须测试资源的数量,判断是否大于可分配的下限值,决定是否予以分配。为使多个进程能互斥地访问某临界资源,只需为该资源设置一互斥信号量mutex,并设其初始值为1,然后将各进程访问该资源的临界区CS置于wait(mutex)和signal(mutex)操作之间即可。

一个菜鸡的博客 1360

Materials Studio与LAMMPS联合作战:如何用msi2lmp.exe完美转换聚合物模型(含PCFF力场配置)

本文详细解析了如何利用msi2lmp.exe工具将Materials Studio中的聚合物模型高效、准确地转换为LAMMPS可识别的data文件,并重点配置PCFF力场。文章提供了从MS模型构建、文件导出到命令行转换、参数调整及转换后验证的全流程实战指南与避坑技巧,旨在帮助研究者解决模型转换中的常见问题,实现跨平台分子动力学模拟的无缝衔接。

weixin_29228781的博客 520

EtherCAT主站SOEM -- 24 -- 基于STM32F767IGT6搭建自己的SOEM-EtherCAT主站

以上就是EtherCAT主站SOEM – 23 – 基于STM32F767IGT6搭建自己的SOEM-EtherCAT主站的内容。有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。创作不容,如果文档对您有帮助,记得给个赞。

常驻客栈的博客--嵌入式EtherCAT 3555

进程内多线程同步CRITICAL_SECTION

来自:http://baike.baidu.com/view/1976662.htm 简介 不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。每个线程中访问临界资源的那段代码称为临界区(Critical Section)。 每个线程中访问临界资源的那段程序称为临界区(Critical Section)(临界资源是一次仅允许一个线程使用的共享资源)。每次只准许

s110600824s的专栏 723

【WRF数据介绍第二期】气象驱动场数据介绍及下载

【WRF数据介绍第二期】气象驱动场数据介绍及下载

WW、forever的博客 2160

使用临界段实现优化的进程间同步对象-原理和实现 (转)

使用临界段实现优化的进程间同步对象-原理和实现 (转) by Jeffrey.Richter Mailto:vcbear@sina.com">vcbear 热情讲解 实现自己的同步对象?需要吗? 不需要吗? ... 只是跟你研究一下而已. 算了吧我只是个爱灌水的家伙,很久没有写代码了,闲来无事,灌灌水还不行吗? 1.概述: 在多进程的环境里,需要对线程进行同步.常用的...

weixin_30758821的博客 121

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

mmap核心原理和用途及其与内存映射段的关系

mmap与malloc/brk的对比、核心功能、工作原理、主要用途、优缺点、与内存映射段的关系、内存映射段的管理机制

2302_80868583的博客 1162

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【Linux进程间通信】Linux匿名管道详解:构建进程间通信的隐形桥梁

当提及Linux系统中的进程间通信(IPC),管道(Pipes)无疑是最基础且广泛使用的一种机制。作为匿名通信的典范,管道为进程间数据交换提供了一个简单而有效的途径。在这个信息飞速传递的时代,掌握Linux管道的使用不仅是理解操作系统底层通信原理的关键一步,也是提升软件开发效率、构建复杂应用系统的必备技能

EterNity_TiMe_的计算机学习之路 4088

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C++进程间通信之SendMessage和PostMessage

C++多进程通信之SendMessage和PostMessage1,使用介绍2,需要注意的地方3,WM_COPYDATA的原理      SendMessage和PostMessage在Win32编程中是很常见的,主要是用来发送消息到指定的窗口,一般用于工作线程传输数据到UI线程。其中SendMessage函数将指定的消息发送到一个或多个窗口。此函...

bajianxiaofendui的博客 1万+

【操作系统/进程间通信】共享内存-原理和实现

共享内存是一种进程间通信的机制,即不同进程的虚拟内存空间(虚拟内存地址不需要相同),

icecreamTong的博客 6306

C++共享内存进程间通信实战:原理、实现与性能优化

进程间通信(IPC)是操作系统和分布式系统中的核心概念,它允许不同进程安全高效地交换数据。其原理在于操作系统提供的多种机制,如管道、消息队列、套接字和共享内存等,每种机制在数据拷贝次数、延迟和适用场景上各有不同。共享内存技术通过映射同一块物理内存到多个进程的地址空间,实现了近乎零拷贝的数据交换,其技术价值在于能够将通信开销降至内存访问级别,从而极大提升高频、大数据量交换场景下的性能。这一特性使其在高性能计算、游戏引擎、实时数据处理和数据库等对延迟敏感的应用场景中成为首选方案。本文聚焦于C++中的共享内存实现

weixin_34326429的博客 291
上一篇: 解开 Windows 下的临界区中的代码死锁
下一篇: 很巧妙的进程防杀方法[秋镇菜原创]
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值