Professional OPC
Development Tools

logos

Online Forums

Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.

Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.

Do not use the Contact page for technical issues.

Running the OPCclient in a separate thread

More
11 Feb 2014 09:54 - 11 Feb 2014 09:55 #1708 by support
Thank you for additional information.

Yes, in your console application, the discussion about synchronization context in my previous post will not apply. You can even block in your main thread, without harming the event notifications coming from EasyAEClient.

The one thing that you should NOT do, is to block for extended periods of time inside the event handler, because if the average time of processing the notifications becomes longer than the average rate of event generation, the internal queues in the component would start to grow (increasing latency) and would eventually overflow, meaning a loss of events.

Best regards
Last edit: 11 Feb 2014 09:55 by support. Reason: clarification - latency

Please Log in or Create an account to join the conversation.

More
10 Feb 2014 17:14 #1707 by guidodebouver
thnaks for your answer, I realized the issue is complciated.

Based on your feedback, instead of placing the OPCClient in the main thread, I realised that I should leave the opclient in the main thread and place the timeconsuming stuff in a separate thread.

Please find the code :

Imports System.Threading
Imports System.Data.Odbc
Module Module1
Dim iodirectorystring As String = "F:\MWorks_CC\"
Dim WithEvents easyAEclient As New OpcLabs.EasyOpc.AlarmsAndEvents.EasyAEClient
Dim bufferstart As Integer = 1
Dim bufferend As Integer = 1
Dim buffersize As Integer = 1000
Dim buffer(buffersize) As String
Dim aTimer As System.Threading.Timer
Dim busy As Integer = 0

Sub Main()
Dim servername As String = ""
Dim OPCserver As String = ""
Dim xml As New System.Xml.XmlDocument()
Dim nl1 As System.Xml.XmlNodeList

REM start here
Console.Title = "MWorks Cause & Consequence Collect OPC"
Console.WriteLine("")
Console.WriteLine("Starting MWorks Cause & Consequence Collect OPC at " & DateTime.Now.ToString)

REM OPC data
xml.Load(iodirectorystring & "MWorksCCCollectOPCConfig.xml")
nl1 = xml.SelectNodes("OPC/Connection")
For Each a As System.Xml.XmlNode In nl1
servername = a.Attributes("servername").InnerText
OPCserver = a.Attributes("OPCserver").InnerText
Next

REM start timer
aTimer = New Threading.Timer(AddressOf tick, Nothing, 2000, 1000)

easyAEclient.SubscribeEvents(servername, OPCserver, 0)

REM continue until quit
Do While Console.ReadLine <> "quit"
Loop

End Sub

Private Sub getOPCData(ByVal sender As Object, ByVal e As _ OpcLabs.EasyOpc.AlarmsAndEvents.EasyAEMultipleNotificationsEventArgs) _
Handles easyAEclient.MultipleNotifications
Dim i As Integer = 0
Dim s As String
For Each x As OpcLabs.EasyOpc.AlarmsAndEvents.EasyAENotificationEventArgs In e.ArgsArray
Try
s = x.Event.ToString
bufferend = bufferend + 1
If bufferend > buffersize Then bufferend = bufferend - buffersize
buffer(bufferend) = s
i = i + 1
Catch ex As Exception
End Try
Next
Console.WriteLine("Added " & i.ToString & " entries in buffer till location " & bufferend.ToString)
End Sub

Private Sub tick(ByVal state As Object)
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim sql As String
If busy = 1 Then Exit Sub
If bufferstart = bufferend Then Exit Sub
busy = 1
If bufferstart > bufferend Then j = bufferend + buffersize Else j = bufferend

REM initialize odbcconnection
For i = bufferstart + 1 To j
If i > buffersize Then k = i - buffersize Else k = i
Console.WriteLine("Processing entry " & k.ToString & " in buffer")
sql = "insert into RAW(data,status) VALUES('" & buffer(k) & "',1)"
Using cn As New OdbcConnection("DRIVER={SQL Server};SERVER=MWORKS\SQLEXPRESS;UID=sa;PWD=passwordpassword;DATABASE=MWORKS_CC_OPC_RAw;")
Dim cmd As OdbcCommand = New OdbcCommand(sql)
cmd.Connection = cn
Try
cn.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
cn.Close()
End Using
Next
bufferstart = bufferend
busy = 0
End Sub

End Module



The main thread is a comnsole application that does not special. I guess this will eliminate all issues you described ???

thank you

guido

Please Log in or Create an account to join the conversation.

More
10 Feb 2014 13:13 #1706 by support
Hello,
the answer depends on where and how your EasyAEClient object is instantiated (where the "New EasyAEClient" statement is).

The event notifications from SubscribeEvents are generated on a separate thread, and there they will normally flow in, even if the thread that called SubscribeEvents completely blocks.

But there is a also a concept of synchronization context. When the EasyAEClient object is instantiated, it attempts to take over the synchronization context of the calling thread (i.e. the thread that instantiates the object). The event notifications are called using the synchronization context, if available. Newly created "plain" threads have no synchronization context. However, if your EasyAEClient object is placed on Windows Forms in a designer and thus created during initialization of the form, the synchronization context will taken from the form itself. This is normally a good thing - it means that your event handler will be called on the main UI thread (the one that is also used to create the form), and therefore you will be able to safely manipulate controls on the form already, without having to switch the threads. On the other side, it also means that if the main thread is blocked, even notifications will be blocked, too.

In order to give you the best advice, please answer first: Is your EasyAEClient object created as part of form initialization? Or is this not in Windows Forms altogether? Please give as much details as possible.
The following user(s) said Thank You: guidodebouver

Please Log in or Create an account to join the conversation.

More
10 Feb 2014 08:58 #1705 by guidodebouver
hello support,

thamk you for this great product !!!

I am trying to run the EasyOPC client in a separate thread.
How can you do that ?
Currently I just have ( VB .NET )

Dim WithEvents easyAEclient As New OpcLabs.EasyOpc.AlarmsAndEvents.EasyAEClient
...
easyAEclient.SubscribeEvents(servername, OPCserver, 0)
...
private sub getopcdata(...) handles easyaeclient.multiplenotifications
...


However, the project contains some extra code that might block the execution of the main thread, so I think the solution is to run the easyOPC cleint and hetopcdata sub in a different thread ?

How can I do this ? Or are there other better ways to achieve the same ?

thnaks again alot for this great product.

guido

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.170 seconds