LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to create parallel tasks using parallel for loops

Solved!
Go to solution

Hi,

 

I am setting up a program that communicates with six logic controllers and has to read the system status every 100 ms. We are using OPC datasockets for this, and they appear a little slow. 

I have created a uniform comm. method for all controllers, and now I find myself programming this method six times to communicate with each system. I am wondering if this could be done more elegant using the parallel for loop, in which case I would program an exchange once and then have six workers running simultaneously. Since a picture is more clear that a thousand words, what I am asking is this:

Is it possible to replace something like

 

parallel-1.png 

 

by

 

parallel-2.png

 

and have this for loop running these tasks in parallel (on different cores / in different threads)?

 

I have configured the loop to create 8 instances at compile, so I would have 2 instances surplus available at runtime if I find I need an additional system.

 

The benefits of the method show in the second picture to me are:

* takes less space

* modifications have to be made only once

* less blocks, wires and stuff makes it more clear what's going on.

* flexibility in the actual number of tasks running (8 instances available at runtime)

* if more tasks are required, I need only to update the maximum number of instances and recompile, i.e. no cutting and pasting required. 

 

Unfortunately, I don't have those system available yet, so there's no way to test this. Yet, I would like to know if the above works as I expect - unfortunately the labview help is not completely clear to me on this.

 

Best regards,

Frans 

Message 1 of 12
(8,446 Views)
Your soloution is definitely prefered to the copy and paste method. I haven't played with parallel loops much so I am not sure if there are any pit falls there. However, a couple of things you could consider. First, you could simply make your "shared" code a subVI and invoke it multiple times in parallel. However adding new devices would still require a recompile of the code. For cases like this Ilike to write the code so that new devices can be added without having to touch the code at all. You accomplish this I would suggest that you read in the number of devices from a configuration file. This way adding a device is as simple as updating the value in the configuration file. If the parallel loop requires you to specify a fixed number of instances then I would write the code to dynamically start the task for the desired number of devices. This would require that you make the task a subVI, which is not a bad thing. It also allows you to adjust your system at runtime rather than at compile time.


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
0 Kudos
Message 2 of 12
(8,418 Views)

Here's how I have approached that:

 

1... Create a controller (state machine) that handles one device.  Everything is stored in shift registers in that VI.

2... Make that controller RE-ENTRANT.

3... Make a copy of that and call it the master.

4... Remove all the code from the master, but keep the front panel as is.

5... Add a DEVICE # to the front panel, to distinguish among the devices.

6... In the diagram of the master, have a CASE structure, based on the DEVICE #.

7... Inside the case, have one of the re-entrant controllers (call it the SLAVE). 

8... Pass all inputs from the master terminals, thru the CASE, and into the slave.

9... Pass all outputs form the slave, thru the CASE, and into output indicators.

10... Duplicate the CASE as many times as you need, one for every physical device.

 

DO NOT CALL the slaves directly from anywhere else.  Call ONLY the master, and tell it which slave to operate.

 

Here is an article which touches on that architecture: 

http://culverson.com/state-of-the-machine/ 

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


LinkedIn

Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 3 of 12
(8,411 Views)

Hi Mark,

 

I also prefer your preferred method, and I think that's what I have done - but correct me if I am wrong.

My configuration is read from a database and stored in an array; additional devices can be added to the database and the program is created such that after adding a device it rereads the total configuration. As said, the config. info is stored in an array, so the number of rows in this array corresponds to the number of tasks that are required to run in parallel - this number I wire to the "P" terminal of the for loop, which determines the number of workers at run time.

The only thing that you cannot dynamically alter is the number of for loop instances that are available, since this is determined at compile time. Therefore, I set this number a bit higher (now: 😎 that the expected number of tasks (now: 6), so I can add two devices without having to recompile the code.

I hope someone with experience on for loops can comment if this strategy works the way the two of us think.

 

-----

 

Hi Steve,

 

I think I grasp the concept of your solution, however, it is not clear to me how the master can run different tasks in parallel, or would that be accomplished by simply calling the master in parallel several times? If so, then that would still require copy pasting of the master.

Also I appears to me that adding an additional devices requires adjustment in the code, which I think is not a nice thing. I would prefer a solution that allows me do add/remove devices dynamically, at run time... at least up to a certain level. If your solution could do this, then let me know, because as said I do not see how it can at this time.

 

 

Thanks for your replies!

Regards,

Frans 

0 Kudos
Message 4 of 12
(8,372 Views)

Here's the actual code which calls four of the devices - yes, there's a loop for each one, but the code here is simple enough that the copy-paste idea is feasible.

 

If the occurrence is triggered, the loops end, otherwise each loop waits a given time - the time it waits is determined by the state machine itself.


Each loop calls the MASTER. The master, in turn calls a specific instance of the slave.

 

The slaves are RE-ENTRANT, and  return quickly, no matter what they're doing.

 

If the master is re-entrant also, then the whole system can overlap, although, if the slaves are written well, that is not essential (in my case, anyway). 

 

 

ForLoops.PNG

 

In my case, there is a max of four devices.  You call the master with various other commands to initiate a CAL sequence, for example (not shown).  These loops just service the state machine.

 

Yes, there is waste if they only use 1 device, but the slaves have an IDLE state, and if a slave is in IDLE, it asks to be called every 1000 mSec.  The ones that are busier can get called faster if they like - each slave tells it's caller how soon to call back. 

 

Whether this fits your needs, I don't know, but it's an idea. 

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


LinkedIn

Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 5 of 12
(8,360 Views)
Given that you may add devicesin the future I would opt for dynamically spawning the individual tasks. This would not require any code modifications and would be driven completely by the number of devices defined in the database. I use this approach for doing mass firmware downloads to printers and spawn as many as 50 tasks which all run in parallel. Using this approach you will need to provide a method for communicating with the individual tasks to control them At a minimum you can use a notifier and a stop command. This would allow you to stop all the running tasks. If you need bidirectional communication you can use queues.


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
0 Kudos
Message 6 of 12
(8,347 Views)

Adding to Steve and Marks postings.

 

If you can understand what Steve is doing, then you may want to review my Nugget on generating Occurences where i posted demo code that launches a bunch of background threads toward the end goal being able to reacreate a real-world version of an Animusic video.

 

 

The narative in that Nugget touches on launching background threads programajicly re-entrancy etc.

 

Under most situation I use queue to comunicate to/from background threads and have delivered apps that used more than 100 background threads.

 

Have fun,

 

Ben 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 7 of 12
(8,337 Views)
Solution
Accepted by topic author Frans_Wijnen
Frans, the parallel for loop will work as you expect in this situation. The six tasks will run in parallel in different threads. What part of the help could be made clearer?
0 Kudos
Message 8 of 12
(8,317 Views)

Dear mfletcher,

 

First of all: thanks for confirming that my intuition was right in this case.

 

As for your question on the help: below is a copy/paste from the help on the 'configure parallelism dialog box' 

  • Number of generated parallel loop instances—Determines the number of For Loop instances LabVIEW generates at compile time. The Number of generated parallel loop instances should equal the number of logical processors on which you expect the VI to execute. If you plan to distribute the VI to multiple computers, Number of generated parallel loop instances should equal the maximum number of logical processors you expect any of those computers to ever contain. Use the parallel instances terminal on the For Loop to specify how many of the generated instances to use at run time. If you wire a larger number to the parallel instances terminal than you specify in this dialog box, LabVIEW only executes as many loop instances as you specify here.
  • The reason for me doubting if what I programmed would work the way I intended lies in the fact that the help only mentions processors here, which would be interpreted as actual cores. Thus on a dual core machine, the number should be 2.

    I think it would be helpful to mention something about threads here, because in some case one would like to have more parallel threads than there are cores in a system.

    In mu case I would like to create six threads, which on my dual core processor would be spread over only two cores. Then these six threads run in parallel.I know that in case of heavy math that would not help, but since I am doing communications, which have timeouts and such, and that probably runs smoother in six parallel tasks even though I only have two cores. 

     

    Hope this helps in improving the help of the for loop.

     

    Regards,

    Frans 

    0 Kudos
    Message 9 of 12
    (8,290 Views)

    Frans,

     

    Thanks for your feedback on the help. I should clarify what I said about threads. If the LabVIEW execution system only has four threads, the six loop instances will cooperatively use those four threads. You can configure LabVIEW to use additional threads in your ini file through a utility VI (see below), but you should see how your program performs before changing the number of threads. More threads isn't always better.

     

    Mary Fletcher

    LabVIEW R&D

     

    How to change the number of threads in the execution system:

    1. Open vi.lib\Utility\sysinfo.llb\threadconfig.vi
    2. Click Configure
    3. Set the system at the top to "Custom System"
    4. Change the number of threads in the table below
    5. Click Save
    6. Stop threadconfig.vi and restart LabVIEW

    If you are curious, you can look in your ini file to see what was added.

    Message 10 of 12
    (8,261 Views)