关于进程间通信和数据队列的一个奇葩问题

cyfage 2015-03-26 04:09:44
在下有一个程序,需要HOOK到目标进程中然后传递数据进行通信。
以前因为传递频率不是很高,简单的使用了内存映射来解决问题,一方创建内存映射并使用定时器随时准备读取数据,另一头读取映射并写入数据。
原本这样的做法没有什么大问题的,可是因为需求的改变,传递数据的频率变得有点高了(其实也就是一秒几次的样子),使得这种传递方式变得好像不是很保险,于是在部分电脑上出现了传递不及时导致程序错误的现象。

为了解决这个问题,我就使用了SENDMESSAGE和COPYDATA的方式来传递数据,又因为传递过来的数据需要在使用时才调用,所以当数据到达时,我使用了一个STL Queue的队列来进行存放。结果,奇葩的问题出现了:在小部分电脑上出现了从队列中取出的数据完全不正确的现象!

刚开始我以为是进程间通信产生的问题,于是在COPYDATA中获取到传递数据时写了调试信息进行记录,结果发现从收到数据一直到PUSH入QUEUE队列的时候都是完全正确的,就是当再次从队列中取出的时候,数据才完全变了样(比如存进去的是2,取出来的变成15之类……)。

收到数据时,我不放心,是先做了记录再PUSH的:
	out_data *data = (out_data*)pCopyDataStruct->lpData;

out_data tmp = {0};
memcpy(&tmp, data, sizeof(tmp));

sprintf(m_log, "收到从HOOK传递过来的数据%d", tmp.num);
Log(m_log);

m_outque.push(tmp);

sprintf(m_log, "将收到的数据PUSH入队列");
Log(m_log);


队列的数据结构也极简单,就是这个样子:
struct out_data
{
int num;
char data[20 * 2];
};


typedef std::queue<out_data> outque;


使用队列的代码都处于同一个线程、同一个类里面,不存在异步问题;而且经过对代码的反复检查,也能肯定除了压入和取出这两处外,没有别的地方对队列进行过任何操作和干涉。这段代码的程序在超过两百台电脑上测试过,绝大部分都运行正常,实际反馈出现这个问题的主要是几台装了WIN7系统,而硬件配置又比较老的电脑。也试过把QUEUE改成Vector,在没出问题的电脑上依旧正常,但出问题的电脑上还是照样出错。

程序的编译环境:VS 2005 MFC DLL程序

不知道有没有人遇到过类似的错误,或者知道问题的根源能够指点一下的?
至为感谢
...全文
159 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
版主大哥 2015-03-28
  • 打赏
  • 举报
回复
引用 12 楼 cyfage 的回复:
[quote=引用 11 楼 xihu1364 的回复:] 应该就是 使用栈内存 那里出现问题了, 不然怎么会有的电脑没问题 有的有问题
其实反过头来想 楼上有些人也没说错 问题肯定出在别的地方,而不是直接出在队列的PUSH上 这种简单直接的队列怎么可能内部出错呢…… 只是不知道出错的具体原因和原理,不知道怎么会影响到队列上了而已……[/quote] 嗯,应该就是内存拷贝的时候,有的机器是因为内存对齐等原因。
版主大哥 2015-03-27
  • 打赏
  • 举报
回复
应该就是 使用栈内存 那里出现问题了, 不然怎么会有的电脑没问题 有的有问题
版主大哥 2015-03-27
  • 打赏
  • 举报
回复
楼主 可以想想啊 容器保存指针和自定义结构体,当自定义结构体比较大的时候,哪个消耗最小? 容器里面是拷贝的。 对于你这个问题,你还有一种解决办法

struct out_data
{
	int num;
	char data[20 * 2];

	out_data& operator = (const out_data& od)
	{
		//自己加
	}
};
就是重载1个=号函数
cyfage 2015-03-27
  • 打赏
  • 举报
回复
客户的运行结果出来了 使用PUSH指针的方式成功解决了问题 多谢楼上各位的帮助 结贴。 不过对于为什么会产生这个问题的原因,依旧希望有看到这个帖子的达人能指点一下,解开这个迷惑。
cyfage 2015-03-27
  • 打赏
  • 举报
回复
多谢楼上各位的指点 关于数据,从目前的角度来说,一直到PUSH之前数据应该是正确的,否则无论如何无法解释日志记录是正确的问题。 我现在试着先NEW内存然后再PUSH指针,取出的时候用完再释放的方法来看看。 因为编译好的程序到用户电脑上运行和反馈需要一段时间,所以暂时没法知道结果——反正我们的测试电脑都是原本就重现不了这个问题的。 但如果这个方法成功了的话,就带来一个很严重的问题:为什么QUEUE或者VECTOR会出现这种现象?经过成千上万次使用、用得好好的东西为什么会出现这种错误呢?或者说到底因为啥我不知道的原因引起的…… 这样的话就麻烦了,以后怎么知道再次使用队列的时候不会出错……
cyfage 2015-03-27
  • 打赏
  • 举报
回复
引用 11 楼 xihu1364 的回复:
应该就是 使用栈内存 那里出现问题了, 不然怎么会有的电脑没问题 有的有问题
其实反过头来想 楼上有些人也没说错 问题肯定出在别的地方,而不是直接出在队列的PUSH上 这种简单直接的队列怎么可能内部出错呢…… 只是不知道出错的具体原因和原理,不知道怎么会影响到队列上了而已……
cutmelon 2015-03-26
  • 打赏
  • 举报
回复
跨进程传数据,用mapfile也没问题吧,sendmessage不可靠的,你程序现在的表现我感觉应该是进程同步问题。 建议使用mutex+event+mapfile 发送方使用mapfile前获取mutex,修改mapfile后释放mutex,置event 接收方等待event,event发生后获取mutext,修改mpafile后释放mutex,继续等待event
oyljerry 2015-03-26
  • 打赏
  • 举报
回复
是不是内存对齐等问题,也要考虑 看上去还是要多加一些日志信息等来分析
版主大哥 2015-03-26
  • 打赏
  • 举报
回复
typedef std::queue<out_data*> outque;
版主大哥 2015-03-26
  • 打赏
  • 举报
回复
楼主试试 使用push指针,这个指针就申请堆上的内存,自己申请和释放 因为你push的时候还是会去拷贝一次,指针的话就4个字节
SiGoYi 2015-03-26
  • 打赏
  • 举报
回复
和使用什么容器没有关系;另外我感觉不是你说的原因,看你代码里也已经做拷贝了,按理说如果是push到队列中还是正确的,那出来时一定是正确。所以感觉学是你push之前就错了,否则就出鬼了。 另外,希望你检查一下“out_data *data = (out_data*)pCopyDataStruct->lpData; ”,这里用的lpData是一个指针,有没有可能在拷贝之前,这个值变了,你可以把使用lpData的地方加上锁式式。
孤客天涯 2015-03-26
  • 打赏
  • 举报
回复
你把临时的数据压入堆栈当然会有问题呀
假正经的班长 2015-03-26
  • 打赏
  • 举报
回复
最好跟踪一下数据究竟是在哪个环节改变的。 可以这样试试,数据一Push进队列,立马取出来,输出,查验一下是否已经被改变 还可以这样试试,把队列编程指针队列,Push进队列时,New对象,将指针Push进去,取出用完后,delete掉 我曾遇到过一次数据莫名其妙被改变的问题,那次是.c和.cpp混用导致的。
Linux系统提供了各种系统调用API用于进程之间的通信:    无名管道PIPE    命名管道FIFO    消息队列    共享内存    信号量    文件锁    信号signal....其中还包括system V和POSIX 两种接口标准,除此之外,Linux系统自身还扩展了自己的一套API接口用于进程间通信,比如signalfd、timerfd、eventfd等。本视频教程为《Linux系统编程》第05期,本期课程将会带领大家学习Linux下将近15种进程间通信IPC工具的使用,了解它们的通信机制、编程实例、使用场景、内核中的实现以及各自的优缺点。本课程会提供PDF版本的PPT课件和代码,学员购买课程后可到课程主页自行下载嵌入式自学路线指导图:------------------------------------------------------------------------------------------------------                   《嵌入式工程师自我修养》嵌入式自学系列教程                                          作者:王利涛------------------------------------------------------------------------------------------------------一线嵌入式工程师精心打造,嵌入式学习路线六步走: 第 1 步:Linux三剑客零基础玩转Linux+UbuntuGit零基础实战:Linux开发技能标配vim从入门到精通基础篇:零基础学习vim基本命令vim从入门到精通定制篇:使用插件打造嵌入式开发IDEmakefile工程实践基础篇:从零开始一步一步写项目的Makefilemakefile工程实践第2季:使用Autotools自动生成Makefile软件调试基础理论printf打印技巧Linux内核日志与打印使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境第 2 步:C语言嵌入式Linux高级编程第1期:C语言进阶学习路线指南第2期:计算机架构与ARM汇编程序设计第3期:程序的编译、链接和运行原理第4期:堆栈内存管理第6期:数据存储与指针第7期:嵌入式数据结构与Linux内核的OOP思想第8期:C语言的模块化编程第9期:CPU和操作系统入门      搞内核驱动开发、光会C语言是不行的!      你还需要学习的有很多,包括:计算机体系架构、ARM汇编、程序的编译链接运行原理、CPU和操作系统原理、堆栈内存管理、指针、linux内核中的面向对象思想、嵌入式系统架构、C语言的模块化编程.....第 3 步:Linux系统编程第00期:Linux系统编程入门第01期:揭开文件系统的神秘面纱第02期:文件I/O编程实战第03期:I/O缓存与内存映射第04期:打通进程与终端的任督二脉第05期:进程间通信-------------------we are here!‍    第 4 步:Linux内核编程‍    练乾坤大挪移,会不会九阳神功,是一道坎。搞驱动内核开发,懂不懂内核也是一道坎。第 5 步:嵌入式驱动开发    芯片原理、datasheet、硬件电路、调试手段、总线协议、内核机制、框架流程....第 6 步:项目实战    嵌入式、嵌入式人工智能、物联网、智能家居...

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧