我工作在一个单线程的OPC客户端程序管理3个不同的西门子PLC连接到同一个OPC服务器,也由西门子。
单线程客户端如下所示:
loop
begin
processPLC1;
processPLC2;
processPLC3;
end;每个processPLC过程调用底层OPC库,例如:
OPCutils.WriteOPCGroupItemValue(FGroupIf, FHandleItemOpc, Value);好的,现在我想在不同的线程中调用每个processPLC并并行工作。
我做了一些研究,并使用OmniThreadLibrary启动了一些代码,但我不认为OPC代码是多线程安全的。是吗?
我应该使用task.Invoke或类似的东西吗?返回ReadOPC标记值的函数如何?这里的最佳做法是什么?
谢谢!
发布于 2013-08-04 22:57:11
我通常看到这样做有两种方式:
1)应用程序有一个由单个线程拥有的OPC客户端实例。当读取/写入OPC值时,所有由客户端应用程序自动化的并行进程都会与拥有OPC客户端的线程使用某种消息传递或同步。
2)每个线程都拥有自己的专用OPC客户端,每个客户端与OPC服务器独立通信。
就我个人而言,我发现最常用的方案是前者;一个OPC (或其他专有的)客户端对象,其线程对客户机进行同步调用。实际上,在几乎所有的进程控制情况下,您都是为了优雅地封装逻辑现实世界任务并将其与UI隔离,而不是为了任何类型的性能而进行多线程处理。这些线程能够承受相对“长”的等待数据的时间--如果需要的话,PLC将很高兴地维持100毫秒的时间。
您选择哪一个在很大程度上取决于应用程序的规模和性质。对于许多花费很长时间等待外部实时事件的轻量级线程,在应用程序中保留一个OPC客户端实例并节省大量独立连接的开销是有意义的。对于少量笨重、快速移动的OPC密集型线程来说,给每个线程提供自己的OPC客户端可能是有意义的。
另外,请记住OPC标记的刷新速率--很多时候服务器只按每100 is左右的顺序更新它们。它可能需要你的PLC至少10毫秒只执行一次扫描,甚至。当数据永远不会快速刷新时,让大量线程以每秒100次的速度独立轮询服务器是没有意义的。
对于进程控制软件,您真正想要的是拥有大量空闲或低负载的CPU时间--线程越轻越好。总体系统响应能力是关键,让您的软件处理高负载情况的能力(突然大量的任务会聚,而操作系统决定是时候索引HDD.可以说,空间可以使齿轮保持润滑状态。大多数线程可能大部分时间都在等待。事件和回调在这里通常是最有意义的。
同时,考虑PLC编程也是很重要的。例如,在我的机器中,我有几个非常关键的操作--同时,每次运行它们都有唯一的时间--这些进程的持续时间是分钟,时间在十分之一秒以下,或者更长,每天重复几百到数千次,每次运行都有一个关键但不同的时间。我见过两种处理方法,一种在软件上,一种在PLC中。对于前一种情况,软件告诉PLC什么时候启动,然后再运行,直到软件告诉它停止。这有明显的缺陷;在这种情况下,只需将时间间隔发送到PLC并让它执行计时就更好了。突然,所有的时间/轮询压力都从软件中消失了,这个过程可以优雅地处理自动化、计算机崩溃等事情。如果你想对OPC服务器的时间关键数据施加很大的压力,那么重新评估整个系统的设计--软件和PLC --往往是值得的。
发布于 2013-08-04 07:24:17
OPC是基于COM技术的,因此也适用同样的规则。如果您想从不同的线程访问OPC服务器,那么每个线程都必须单独调用CoInitialize和CoUninitialize。
它很可能与从不同进程访问OPC服务器相同。OPC服务器本身是单线程还是多线程并不重要。
您可能遇到的障碍是您正在使用的OPC客户端库的抽象。
发布于 2013-08-05 06:23:57
IMHO --看起来你在过度设计它,最好尽量保持简单,但是添加线程并不能使事情变得更简单。
如果您有多个OPC服务器,那么线程可能是一个更好的抽象,但是现在您只需要一个到一个OPC服务器的连接,然后拥有多个线程和多个连接似乎过于复杂,而没有太多的实际收益。
相反,使用常规的OPC订阅机制按顺序读写,就像以前一样。
https://stackoverflow.com/questions/18040338
复制相似问题