C++多线程 CPU利用率100%,怎么解决?

hongss 2019-02-03 03:07:34
项目大概:
1、程序需要采集伺服电机A/B相脉冲信号(2500Hz),通过板卡IO口进行采集;
2、IO板卡同步采集两个限位信号,常态为高,电机带动部件碰到限位时,为低。即低有效;
3、另一板卡采集一信号,板卡AD,但是频率较慢,大概300Hz;
4、另一计算机远程登录到本计算机进行远程监控,也可远程操作。

采用双线程进行编程:
线程1,采集IO信号,遇到上升沿进行脉冲计数,同时判断限位状态,以控制伺服电机转向;
线程2,采集AD信号,根据线程1的脉冲计数进行位置甄别,计算、显示数据;

遇到问题:
1、程序运行时,CPU使用率大部分时间为100%;
2、远程计算机登录后,由于CPU使用率过高,鼠标移动也会造成数据采集失误;
3、2.5KHz的脉冲信号采集也会丢步。。。

现在主要问题应该是如何减低CPU使用率?

请做过此类项目的大侠们指点指点~~

BTW:大年二十九了,给论坛的兄弟们拜个早年!!!


...全文
2043 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
hongss 2019-04-08
  • 打赏
  • 举报
回复
唉,BOSS不愿意增加单片机,只好采用伺服电机输出频率降频的方式,将两个线程合并到一个里,同时将最低频率的电压采集改写了下,将AD转换的中间等待时间开放给数脉冲及其他外购的电压采集卡采集。 用这样的方式倒是可以,CPU占用率也只有60%左右,代价是牺牲了计算宽度的精度,降低了一个数量级。。。 结贴了,谢谢诸位的帮助。
titan_ysl 2019-03-19
  • 打赏
  • 举报
回复
单片机常用的有51系列,stc、avr、stm等,和计算机之间可直接用usb通讯,但这要高档的芯片才支持,且电脑端还要编usb驱动,实现起来比较复杂,你的任务这什么做是杀鸡用牛刀。就用低端的芯片,通过uart串口,再用CH340或PL2303等UART接口转USB接口模块传给电脑,电脑端装接口模块的usb转串口驱动,单片机和程序用串口通讯就行。 单片机端,直接控制电机的转向、数脉冲,同时接收串口的查询。 计算机端,在需要用到脉冲数据时,再通过串口去查询。
  • 打赏
  • 举报
回复
这要看“控制伺服电机转向”的实时性要求高不高,也就是你读到低电平限位信号和控制伺服电机转向之间的延迟可以允许多少时间,如果可以有几十毫秒的延迟,完全可以用文件方式打开I/O卡(应该是模拟为串口设备),这样信号是不会丢的,只是出现低电平脉冲信号和你的程序读到并处理之间的间隔无法保证。
hongss 2019-03-18
  • 打赏
  • 举报
回复
谢谢各位的支招! 用单片机的话,单片机和计算机之间用什么通讯方式更好一些?串口? 另外,单片机数脉冲,再发给计算机,不一样要计算机来处理位置信号么?就算数到100个脉冲输出一个位置给计算机,不足100的脉冲数怎么办?对单片机已经忘得差不多了,请有经验的伙伴们给点详细的指导意见,谢谢啦~~~ BOSS貌似不愿意增添新的硬件,就想用软件怎么解决了了事
vc_dreamver 2019-03-08
  • 打赏
  • 举报
回复
这个设计方案不是太好。
系统本来是一分时的操作系统,2K多的采样要求时间片切换很频繁,线程越多反而越不好。
系统定时器精度也没有这么高的,没有中断方式可用,只能查询方式,即使采用QueryPerformanceCounter也
不能保证采样精度。最好的方法如上面的朋友提出的,用一个几元的单片机就可以完美解决这些问题,而且精度
也能够得到保障。
hongss 2019-02-19
  • 打赏
  • 举报
回复
将最低频率的电压采集改写了下,将AD转换的中间等待时间开放给数脉冲及其他外购的电压采集卡采集,结果发现,CPU使用率倒是下来了,最高也就60%(只有简单的界面处理),但数脉冲的频率也下来了,只有正确脉冲数的1/3左右。。。

看来这个也不行啊。。。
xjl7488562 2019-02-17
  • 打赏
  • 举报
回复
线程调度问题,两个线程之间没有联系吗?当一个休息的时候另外线程就得干活
qq_183294704 2019-02-15
  • 打赏
  • 举报
回复
引用 9 楼 早打大打打核战争 的回复:
[quote=引用 6 楼 hongss 的回复:]
看了楼上二位的说法,感觉这套系统的结构就存在问题~~~

可能以前采集220K信号时,本来就在低于1K的丢失脉冲时,在大基数脉冲信号时,比例很小,可能就忽略了~

那么,请问诸位,这样的情况下,无解了?有没有什么办法能使得这个脉冲的计数能准确一些?


没有很好的办法,除非写驱动或者在DOS下做,两者本质一样,都是编程一个高频时钟中断,比如CMOS实时时钟中断,可以很容易达到中断率32KHz或者更高。不过你的信号是低电平有效,实际有效频率取决于这个低电平信号的最短持续时间,换算成有效频率,采样频率不低于信号频率的2倍就可以保证采样精度,如果不超过500Hz,用多媒体计时器设置一个1ms的回调是完全可以的。另外看你的采集卡能不能工作在中断方式,而不需要软件一直查询,如果能设置为采集到低电平信号中断就好多了。
提高线程优先级,聊胜于无吧,但是会造成系统更卡顿的。
[/quote]楼上的有经验,在选择IO卡时一般都会看IO卡有没有带中断的高速IO点,如果没有,这个问题就解决不了。
titan_ysl 2019-02-15
  • 打赏
  • 举报
回复
系统的界面处理(数据显示、图表绘制),这些在线程中处理是需要同步的,会严重影响数据的采集,千万不要放在同一线程中,如界面处理不是很占用cpu,就放在主线程中是最好的,既方便,又不容易出错。 
hongss 2019-02-15
  • 打赏
  • 举报
回复
引用 14 楼 qq_183294704 的回复:
楼上的有经验,在选择IO卡时一般都会看IO卡有没有带中断的高速IO点,如果没有,这个问题就解决不了。


我的IO卡,是公司自制的,主芯片采用8255A,加上一些外围电路。
hongss 2019-02-15
  • 打赏
  • 举报
回复
引用 9 楼 早打大打打核战争 的回复:
没有很好的办法,除非写驱动或者在DOS下做,两者本质一样,都是编程一个高频时钟中断,比如CMOS实时时钟中断,可以很容易达到中断率32KHz或者更高。不过你的信号是低电平有效,实际有效频率取决于这个低电平信号的最短持续时间,换算成有效频率,采样频率不低于信号频率的2倍就可以保证采样精度,如果不超过500Hz,用多媒体计时器设置一个1ms的回调是完全可以的。另外看你的采集卡能不能工作在中断方式,而不需要软件一直查询,如果能设置为采集到低电平信号中断就好多了。
提高线程优先级,聊胜于无吧,但是会造成系统更卡顿的。


试着从最低频率采集的驱动入手测试了一下,将所有数脉冲和采集数据放置到同一个线程,同时将AD转换中间的等待时间开放给数脉冲,貌似可以解决,此时还未加入系统的界面处理(数据显示、图表绘制),CPU使用率在60%左右。

看到曙光了,继续往下走……
titan_ysl 2019-02-13
  • 打赏
  • 举报
回复
如果对脉冲的精度要求高,不能漏数,建议用单片机来采样,之后,再把信号传给电脑。 如要求不高,允许漏数, 则直接用电脑来收也将就用。AD采样比IO慢是AD转换慢,其一般应有个转换完成标志,在能读取时,速度还是很快的。你可以在AD线程中只执行AD采样代码,循环中不延时,timeGetTime()来计时,算出采样代码的执行时间,如耗时短,小于或接近脉冲信号的周期,则可以在io线程的循环中,在循环了一定次数后,插入AD采样代码。
hongss 2019-02-13
  • 打赏
  • 举报
回复
引用 8 楼 titan_ysl 的回复:
数脉冲时丢失,不是cpu来不及数,当cpu在处理你的这个线程时,工作频率是完全能跟上的,丢失脉冲是cpu在切换线程和处理其它线线程任务时才丢失的。如你的这个线程一直在运算,cpu是会分配更多的时间片给你的这个线程,这样这个线程就能有更多的时间运行。且现在cpu的速度,数脉冲时,大部份时间都是空闲的,这时完全可以用来做其它的事。
另外,一个线程,如果不停地运算,大概要占用30%或以上的cpu资源,两个这样的线程就要占到60%以上了,而你在两个线程中作的事,在一个线程中完全可以完成,所以大可放到一起来做,省下的cpu资源可用来及时响应其它的外部消息。
还有,你可用
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
来提升自己程序的执行优先级,来获得更多的cpu执行时间。


刚又测试了一下,如果只是数脉冲,CPU的使用率一直在50%左右。

你说得对,很有可能是在处理其他线程时丢失了。现在是总脉冲数在30K~48K之间,根据行程的长短变化,每次单趟数完后,可能会丢失最多600左右,找不到在哪里丢失的~~~~~

如果把数脉冲和采集数据放到一个线程做,在采集数据380Hz和脉冲频率在2500Hz时,线程会不会在采集低频信号的时候,漏掉了高频信号?

另外,我把电机脉冲进行分频,降低测量精度,依然会丢失一些。。。
hongss 2019-02-12
  • 打赏
  • 举报
回复
引用 4 楼 titan_ysl 的回复:
本来用电脑来数脉冲就已很浪费cpu资源了,你还开两个线程来做这事?
正确的做法是把上了1khz的脉冲信号采集交给单片机来做,电脑只收集1Khz以内的信号,使用多媒体计时器来算时间。
如非要用电脑来收集,则把所有的信号采集和耗时的处理都放到一个线程中,自己想法分配好时间占用比率,在别的线程中只作不费时的事,这样就可留下较多的cpu资源来处理别的事了。 



如果“把所有的信号采集和耗时的处理都放到一个线程中”这样的话,数脉冲时,丢失不就更严重了么?
hongss 2019-02-12
  • 打赏
  • 举报
回复
看了楼上二位的说法,感觉这套系统的结构就存在问题~~~

可能以前采集220K信号时,本来就在低于1K的丢失脉冲时,在大基数脉冲信号时,比例很小,可能就忽略了~

那么,请问诸位,这样的情况下,无解了?有没有什么办法能使得这个脉冲的计数能准确一些?
  • 打赏
  • 举报
回复
引用 10 楼 qq_44245521 的回复:
线程撕裂者了解一下,土豪专享


这倒是提供了一个思路,可以安装实时扩展,诸如X-Realtime (https://www.sybera.com/)、kithara(https://kithara.com/en),这些扩展本质上是通过驱动独占了若干核心/处理器来执行实时任务。
qq_44245521 2019-02-12
  • 打赏
  • 举报
回复
线程撕裂者了解一下,土豪专享
  • 打赏
  • 举报
回复
引用 6 楼 hongss 的回复:
看了楼上二位的说法,感觉这套系统的结构就存在问题~~~

可能以前采集220K信号时,本来就在低于1K的丢失脉冲时,在大基数脉冲信号时,比例很小,可能就忽略了~

那么,请问诸位,这样的情况下,无解了?有没有什么办法能使得这个脉冲的计数能准确一些?


没有很好的办法,除非写驱动或者在DOS下做,两者本质一样,都是编程一个高频时钟中断,比如CMOS实时时钟中断,可以很容易达到中断率32KHz或者更高。不过你的信号是低电平有效,实际有效频率取决于这个低电平信号的最短持续时间,换算成有效频率,采样频率不低于信号频率的2倍就可以保证采样精度,如果不超过500Hz,用多媒体计时器设置一个1ms的回调是完全可以的。另外看你的采集卡能不能工作在中断方式,而不需要软件一直查询,如果能设置为采集到低电平信号中断就好多了。
提高线程优先级,聊胜于无吧,但是会造成系统更卡顿的。
titan_ysl 2019-02-12
  • 打赏
  • 举报
回复
数脉冲时丢失,不是cpu来不及数,当cpu在处理你的这个线程时,工作频率是完全能跟上的,丢失脉冲是cpu在切换线程和处理其它线线程任务时才丢失的。如你的这个线程一直在运算,cpu是会分配更多的时间片给你的这个线程,这样这个线程就能有更多的时间运行。且现在cpu的速度,数脉冲时,大部份时间都是空闲的,这时完全可以用来做其它的事。 另外,一个线程,如果不停地运算,大概要占用30%或以上的cpu资源,两个这样的线程就要占到60%以上了,而你在两个线程中作的事,在一个线程中完全可以完成,所以大可放到一起来做,省下的cpu资源可用来及时响应其它的外部消息。 还有,你可用 SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); 来提升自己程序的执行优先级,来获得更多的cpu执行时间。
  • 打赏
  • 举报
回复
引用 3 楼 hongss 的回复:
我用单线程采集IO口,用信号发生器产坐方波信号,可以达到220K的采集频率,几乎没有丢步的。现在才2.5K,应该不会有多大问题吧?

换计算机能解决CPU使用率过高的问题?通过编程有办法解决么?


除非你的采集卡带缓冲,实时采集这么高频率不可能不丢,你计数一下每秒采集的信号数量就知道了。之所以你感觉“几乎没有丢步的”,是因为你采集的信号常态为高低有效,恰好丢失低电平信号的概率比较低而已。
windows本来就不是实时操作系统,不写驱动只在应用层处理,最高精度也就是1ms级别,要实时处理高频信号,用µC/OS、VxWorks
加载更多回复(4)

604

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder VCL组件使用和开发
社区管理员
  • VCL组件使用和开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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