LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

read ini file with multiple threads

I have a state machine architecture, but I have multiple threads. For instance, one is dealing with listening for mulitple tcp connections and storing their refnums to an array in a functional global. Another thread is accessing these refnums and collecting data it's receiving from each tcp connection. This data is queued up and then dequeued in a third thread which does some modification and sends it out via serial. My question is, when you have a situation like this and have to read an ini file, where should you read it? It seems like the most logical place would be outside your loops so you can get all the tcp and serial info (port, baud rate, etc) then wire it it to your create listener or initialize serial connection despite them being in different threads. But then again, normal state machine architecture would want an "initialize" case. If you did this though which loop would you put the init case in? And you would then have to worry about synchronizing loops becuase you wouldn't want one to try and create a listener while another thread was still reading ini data which would include the port to listen on. Maybe I'm overthinking this haha. Suggestions?
Edit: one more question. Does it seem overkill that I have a tcp loop listening for data and queuing it up and a separate loop sending out the processed data via serial? Or should I just have one state that gets tcp data stores it in a shift register, then another state that sends it out via serial, and returns the state machine to the tcp read state?
Message Edited by for(imstuck) on 03-03-2010 01:13 PM
Message Edited by for(imstuck) on 03-03-2010 01:17 PM
0 Kudos
Message 1 of 8
(3,417 Views)

I generally read all of my configuration data in the beginning of my application before I start my other tasks. However, in many of my applications I use profiles which the user can load during runtime so I do need to provide a means for that data to be propagated to all tasks. In most cases this is easy since the shared resources are singleton objects and the processing of the new profile simply sets the appropriate attributes on the objects.

 

As for your second question it depends on how much data and how quickly you need to read it. If you have a fairly large, continuous stream of data I would read it in one task and pass it off for processing in another. If your data is relatively small and not coming in very fast I would probably use a single state machine. I have used both approaches and it really depands on your processing tasks and how much data is flowing through the system.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
Message 2 of 8
(3,395 Views)

I won't address the TCP loop overkill question without a bit more info-  I think its going to be pretty use specific but if it works and is maintainable without performance issues I'd say leave it alone.

 

Where to read the ini and use it in multiple places is however easy to answer.  The no-brainer solution is to read it in an action engine.

 

Ben has a great nuggetwith some pretty great details-  I'll just link you there as I'm not going to try to top his knightlyness


"Should be" isn't "Is" -Jay
Message 3 of 8
(3,392 Views)

Mark Yedinak wrote:

I generally read all of my configuration data in the beginning of my application before I start my other tasks. However, in many of my applications I use profiles which the user can load during runtime so I do need to provide a means for that data to be propagated to all tasks. In most cases this is easy since the shared resources are singleton objects and the processing of the new profile simply sets the appropriate attributes on the objects.

 

As for your second question it depends on how much data and how quickly you need to read it. If you have a fairly large, continuous stream of data I would read it in one task and pass it off for processing in another. If your data is relatively small and not coming in very fast I would probably use a single state machine. I have used both approaches and it really depands on your processing tasks and how much data is flowing through the system.


With the answer to my second question, that's pretty much what I figured. As for the first answer, could you go into a little more detail about the bold part, possibly with an example (not necessarily with sample code, a description works too)?

0 Kudos
Message 4 of 8
(3,390 Views)

Jeff Bohrer wrote:

I won't address the TCP loop overkill question without a bit more info-  I think its going to be pretty use specific but if it works and is maintainable without performance issues I'd say leave it alone.

 

Where to read the ini and use it in multiple places is however easy to answer.  The no-brainer solution is to read it in an action engine.

 

Ben has a great nuggetwith some pretty great details-  I'll just link you there as I'm not going to try to top his knightlyness


Thanks, Jeff. I have read that action nugget many-a-time. I guess my real issue is, the tcp listener is created once. I would use an action engine to pass the data. However, my issue is, if the thread starts before the action engine is initialized, then I don't have the current ini data stored in the AE yet. Therefore, I think it is best to load my ini data to an AE outside any loops and allow data flow to insure this is done before entering my different threads.

Message 5 of 8
(3,386 Views)

Correct!

You need to establish a known starting state.  Or in the example from Mark, a dynamic state of the data.  The First Call? function can be a great tool for checking that the first call to your AE is an Init call.  (If it isn't-loop to the init state first then the desired state)  


"Should be" isn't "Is" -Jay
0 Kudos
Message 6 of 8
(3,382 Views)

Most of the applications I work on at the moment are used for testing barcode and label printers. The test applications I design are focused on testing the printer's firmware, not the hardware. Within our applications we have three primary objects (Unfortunately they are not native LabVIEW objects yet. They were developed before native LVOOP.) The primary objects we use in our applications are a log object, a connection object (communication interface to the printer) and a printer object. In any single instance of a test we only have a single printer, a single connection to the printer and one or more discrete logs. Each instance of these objects represent a single, real physical entity. A singleton object is a virtual representation of the physical world. Let's take the log object since that is the most simple of the objects described above. Naturally for a given log file you have the log file name and path. We also provide other attributes such as the maximum size of a single file (we allow log files to span multiple files), whether it is a comma delimited file or if it contains raw data, if timestamps should be included with a log entry and so forth. Most of these attributes are static for a log file with the exception of the name and such things as whether the logging is actually enabled or disabled. If we split a wire and had multiple instances of the log file (the way native LVOOP actually works) the attribute for whether logging is currently enabled or disabled will only pertain to the specific instance, or specific wire for the that object. Since this truly represents a single item, one log file, we need that attribute to be shared for all references to the instance of the log object. Since we allow this we can set an attribute on the log object in any task and it will be reflected in any other task that is using it. Think of the way a action engine or functional global works. However, in this case we provide discrete methods for the various actions.

 

I hope that made some sense. If not let me know since I just whipped up this response.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
Message 7 of 8
(3,378 Views)

for(imstuck) wrote:
...

Thanks, Jeff. I have read that action nugget many-a-time. I guess my real issue is, the tcp listener is created once. I would use an action engine to pass the data. However, my issue is, if the thread starts before the action engine is initialized, then I don't have the current ini data stored in the AE yet. Therefore, I think it is best to load my ini data to an AE outside any loops and allow data flow to insure this is done before entering my different threads.


 

 

I am forcing myself to learn OOP for use in LVOOP and there is a pattern (?) rule that I think is called "Expert". The idea associated with that rule is an object can gets its configuration from who ever knows the info when it is started. I believe you have discovered the same rule but with some twists since this is not LVOOP. The mechanism used to pass the data is your call but the idea of putting the data somewhere so the seperate thrad can find it when it starts fits with the fancy-schmancy theory.

 

Re: your question about using a queeu between TCP/IP and serial

 

Another good idea! You don't want teh TCP/IP traffic to be throttled by the serial speed. Queues are nice buffers between threads that run at different speeds.

 

Ben

 

PS If you know OOP and think I got the above wrong... well correct me before I leads others astray. Smiley Wink

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 8 of 8
(3,370 Views)