• 全部
  • VC综合技术
  • 互联网技术
  • MFC AppLauncher
  • .NET 技术
  • 界面
  • 进程
  • 算法
  • 硬件/系统
  • 数据库
  • VC++技术资源

一个buffer 怎么样处理最快???

oktsl 2009-08-19 04:14:29
线程等待,一旦串口有数据过来,读出数据,写到一个长度为1024的buffer里,
串口不断有数据过来,不断往buffer里面加,buffer满了,就回到buffer头部重新加
处理过程是这样:串口一有数据过来,立刻写到buffer里,然后就开始处理

然后老板说,这样太慢了

如果串口发送速度快,处理又比较慢的话,如果还没处理完,新的数据又来了,会丢掉串口数据的
所以要一个比较快的处理办法

我想的办法是:
把写buffer和处理 分成2个线程
1个线程不停的写,一有数据过来,就加到buff
1个线程不停的从buffer读,然后处理
这样是不是快点,还有没有更好的办法,多谢了
...全文
286 点赞 收藏 26
写回复
26 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
oktsl 2009-08-24
刚好一人一分 ,见笑了
回复
oktsl 2009-08-21
[Quote=引用 10 楼 heksn 的回复:]
你可以设置读写标识  将两个标识之间的数据整体读取
[/Quote]

我就是这样做的,读取2个标识之间的数据 但是如果写的速度太快,写的标识超过读的标识一个buffer身位
就会出问题啊
回复
vcmfcjavabbs 2009-08-20
一个读线程, 一个写线程,这样做很好。但是线程同步,这就不必了吧。动态增长的缓冲区,算了吧。循环链表,解决不了问题。
线程同步,两个线程不能同时工作,能提高速度吗?
动态增长的缓冲区,开玩笑。读线程从哪里读,写线程写在何处?
循环链表,不要以为数据结构用在哪里都能解决问题。
有一个办法,不知道大家以为好不好。
(1)一个读线程, 一个写线程。这两个线程不需要同步,各自独立工作。
(2)读线程动态申请一个缓冲区。一旦缓冲区满,把缓冲区地址和长度告诉写线程。
(3)重复(2)
有人可能要问了,那写线程还是来不及处理,怎么办?你管它来不来得及处理。反正我已经把任务交给你了,你什么时候完成什么时候休息。所以
(4)写线程维护一个任务队列,队列结点为读线程送来的缓冲区地址和长度。写线程依次处理队列中的缓冲区,处理好之后,释放缓冲区。
这样做,虽然仍然可能有缓冲区在写线程那里积压,但至少读线程来得及读,不至于loss数据。
回复
vcmfcjavabbs 2009-08-20
wenfh2020说:难道这个不是“同步”?
我们在很多时候,都应该换个角度思考。操作系统课程里讲过PV操作,讲过读、写线程如何同步。于是很多人就会生成一种定性思维,只要遇到读/写问题,就用PV对公共缓区实施封锁。但是Pv影响效率,因为一个线程要等另一个线程的信号,也就是说线程会经常处于等待不做事的状态。不过不用PV,访问冲突不可避免。所以同步的关键是如何PV,在何处PV。在上面的串口例子,我们是不能对存储串口数据的buffer实行PV。换一种方式,我们在另一个地方PV。
  在上面的串口的例子了,读和处理完全不要同步(我这里讲不要同步,是指读线程读串口数据写入buffer和处理线程处理buffer不要同步)。这种方案,是我以前在写网络聊天程序时想出来的。我当时在这个程序的客户端里用一个sock来接收所有数据,这些数据会分发到其它的窗口。大家想想QQ,每个QQ用户都有多个好友,可能和多个好友聊天,一个sock接收所有进来的数据,然后再送到对应的聊天窗口。当然在这种窗口环境中,我们要把数据交给窗口(我们可以把窗口看作线程)很简单,用PostMessage(hWnd, MESSAGE_ARRIVE, buf, len)就可以了。在聊天窗口的MESSAGE_ARRIVE响应函数里,处理buf,处理完之后,delete buf.需要强调的是,这个buf是接收线程动态申请的,即buf = new char[SIZE],而且接收线程每次接收数据都要这么做。
那么,各位朋友,这样做,接收线程和聊天窗口同步了吗?没有。真的没有。而且这样做,不会发生任何的冲突。接收线程每次接收数据都buf = new char[SIZE],然后它把这个缓冲区的地址和长度告诉处理窗口,之后由处理窗口来释放这个缓冲区.这里的要点是,接收线程接收完数据后,它就再也不用这个buf了,它重新申请一个。
  在窗口环境中,我们有消息队列。消息队列使得我们的方案得以实现。所以在串口的例子中,我们也就可以做一个队列。为方便起见,这个队列是全局的。
程序如下:
#define BUFFER_SIZE 1024
QUEUE queue;
CEvent event(true); //用于线程同步,初始时,置event为有信号状态
UINT ReadProc(LPVOID lParam){
while(串中还在工作?){
int nCurSize = 0, nBytes = 0;
char *buf = new char[BUFFER_SIZE];
while(1){
读串口,写入buf;
nBytes == 此次读到的字节数;
nCurSize += nBytes;
if(nBytes == BUFFER_SIZE){ //注意BUFFER_SIZE应该是串口端口长度的整数倍
::WaitForSingleObject(event.m_hObject, INFINITE);
queue.Enqueu(buf, len); //缓冲区地址'长度入列
event.SetEvent();
break;
}
}
}//EndWhie(串口还在工作?)
}//EndProx

UINT ReadProc(LPVOID lParam){
char *buf;
int len;
while(1){
::WaitForSingleObject(event.m_hObject, INFINITE);
bool bl = queue.Dequeue(buf, len); //取队头元素Dequeue形参类型为引用
event.SetEvent();
if(bl == true && buf == 0)
break;
if(bl == true){
处理buf;
delete buf;
}
}
}
线程同步,只是在入队和出队这里。我想入队和出队的执行时间没有处理buf的时间长吧。

回复
LPR_Pro 2009-08-20
采用serail类处理,已经封装好串口通信,该类可以实现LZ的想法.
下载地址:
http://www.pudn.com/downloads/sourcecode/windows/network/detail585.html
回复
njlengjiang 2009-08-20
学习
回复
wenfh2020 2009-08-20
[Quote=引用 12 楼 vcmfcjavabbs 的回复:]
一个读线程, 一个写线程,这样做很好。但是线程同步,这就不必了吧。动态增长的缓冲区,算了吧。循环链表,解决不了问题。
  线程同步,两个线程不能同时工作,能提高速度吗?
  动态增长的缓冲区,开玩笑。读线程从哪里读,写线程写在何处?
  循环链表,不要以为数据结构用在哪里都能解决问题。
  有一个办法,不知道大家以为好不好。
  (1)一个读线程, 一个写线程。这两个线程不需要同步,各自独立工作。
  (2)读线程动态申请一个缓冲区。一旦缓冲区满,把缓冲区地址和长度告诉写线程。
  (3)重复(2)
  有人可能要问了,那写线程还是来不及处理,怎么办?你管它来不来得及处理。反正我已经把任务交给你了,你什么时候完成什么时候休息。所以
  (4)写线程维护一个任务队列,队列结点为读线程送来的缓冲区地址和长度。写线程依次处理队列中的缓冲区,处理好之后,释放缓冲区。
这样做,虽然仍然可能有缓冲区在写线程那里积压,但至少读线程来得及读,不至于loss数据。
[/Quote]

难道这个不是“同步”?
回复
俺常年做这种边接收边处理的事情,只要采用内存循环使用的办法,多线程,缓冲够大,绝对没问题。
回复
happysalay 2009-08-20
首先,你使用1024字节的缓冲区意义不大,pc的串口读写本来就带缓存的,我记不清楚多大了,但至少有1024bit。
第二,要分析你老板说的数据冲掉的原因,一般有两种可能
1、平均处理速度小于IO数据接收速度
2、处理数据时正好有数据到达,因为单线程,没有中断不能及时响应面丢数据。

情况一正像vieri_ch说的,这个不常见,如果真是这种情况的话,你用两个线程也解决不了问题,
除非申请一块足够大的缓存,几乎可以存下整个过程中串口读取的数据;或者优化处理过程(如多线程处理)使平均处理速度大于IO数据接收速度。

情况二很少单独发生,正如前面所以,串口本来就带有缓存,问题就是缓存是否够大,这种情况下按你的想法,采用双线程,使用大容量的环形缓冲区自然可以解决问题。
回复
FlySkyFree 2009-08-20
进来学习下
回复
w29468 2009-08-20
可以用“乒乓写”的方式,两片缓冲区,写进程轮流写,一个写满后再写另一个;读进程只读已经写满的一个。这样锁保护比较高效。另外读的处理速度肯定需要保证高于写的速度,那不然怎么都会有数据堆积或丢失
回复
我辣椒哥 2009-08-20
学习了
回复
尘雨 2009-08-20
串口IO的速度远慢于内存IO速度,所以从理论上来说,只要你的程序没有逻辑错误,处理buffer的速度远高于串口IO速度。除非处理buffer的线程堵塞。

串口IO的速度也慢于磁盘文件IO速度。

方案如下

读串口--->存入buffer--->投递一个消息给buffer处理线程,这个过程不会堵塞
建议buffer不要少于2M,现在内存都很便宜,不要太过吝啬。

处理buffer的线程。根据事件消息,块读buffer--->写入磁盘文件--->清空buffer。

只要处理好内存IO和文件IO时的异常处理,不要堵塞这个线程。就不会出现串口IO数据积累过多,而来不及处理的情况。

buffer结构的设计。建议用stl库的容器模板类。

对于几个串口的同时接收,内存和磁盘IO远远快于串口IO,所要做好的仅仅是设计好线程不要因为意外发生堵塞。对队列的同步,其他人说的都很多了

回复
wish_cn 2009-08-20
[Quote=引用 12 楼 vcmfcjavabbs 的回复:]
  一个读线程, 一个写线程,这样做很好。但是线程同步,这就不必了吧。动态增长的缓冲区,算了吧。循环链表,解决不了问题。
  线程同步,两个线程不能同时工作,能提高速度吗?
  动态增长的缓冲区,开玩笑。读线程从哪里读,写线程写在何处?
  循环链表,不要以为数据结构用在哪里都能解决问题。
  有一个办法,不知道大家以为好不好。
  (1)一个读线程, 一个写线程。这两个线程不需要同步,各自独立工作。
  (2)读线程动态申请一个缓冲区。一旦缓冲区满,把缓冲区地址和长度告诉写线程。
  (3)重复(2)
  有人可能要问了,那写线程还是来不及处理,怎么办?你管它来不来得及处理。反正我已经把任务交给你了,你什么时候完成什么时候休息。所以
  (4)写线程维护一个任务队列,队列结点为读线程送来的缓冲区地址和长度。写线程依次处理队列中的缓冲区,处理好之后,释放缓冲区。
这样做,虽然仍然可能有缓冲区在写线程那里积压,但至少读线程来得及读,不至于loss数据。
[/Quote]

你这个“写线程维护的任务队列”怎么也得是一个顺序表吧,如果读线程往这个队列里写,写线程从这个队列里读,那要不要同步呢?
如果由写线程自己维护,那读线程通过什么方式把地址和长度给写线程呢?假如给的时候写线程正在忙着处理数据,读线程该不该等?等久了会不会丢数据?
回复
wish_cn 2009-08-20
to vcmfcjavabbs:

你说的这种方法说白了还是要同步的,楼上的已经提到这个方法了,而且临界区也只限于读写队列的部分,并没有说把处理数据的部分也做同步。
而PostMessage/GetMessage/PeekMessage用的是GUI线程的消息队列,系统已经帮你把同步工作给做好了。COM的STA套间就是用这个消息队列来处理方法调用的。
回复
fly4free 2009-08-19
楼主不会根据这些数据进行大规模科学计算吧?
回复
你可以设置读写标识 将两个标识之间的数据整体读取
回复
zgl7903 2009-08-19
用一个循环队列, 在从串口读数据之前检查队列是否满,满则动态调整缓冲区大小, 数据加入到队尾
处理数据从对头取数据 取之前判断是否是空,
回复
cutestar 2009-08-19
统计下一次传输数据的最大长度,以此长度为基本,分配一块大的空间,形成环形链表,计算1ms接收的消息数最大值,处理时间等,然后2个线程依次处理链表中的数据,用一个标识来记录当前节点状态
回复
oktsl 2009-08-19
处理数据的速度必须大于串口来数据的速度
这个没必要吧,比如说串口来了数据70B,我写到buffer里面,然后write指针指到80
下一次来数据了,接着写进去,write指针再加
读数据处理的时候需要判断的,如果70B不是完整的一段需要处理的消息,会pass过去,可能2.3句话才真正需要处理1次

老板说,可能1mS会有很多消息过来,而每次处理消息显然处理不了
回复
相关推荐
发帖
VC/MFC
创建于2007-09-28

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2009-08-19 04:14
社区公告

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