LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Making Call library function to run in any thread

As Wiebe said, as long as you call the DLL functions always in sequence and never ever parallel anywhere in your program, you are not really exercising its thread safety (very much). The very much in brackets is because there is a chance that a DLL actually makes use of thread local storage and then it still could fail if the DLL assumes that all calls are always made from the same thread. This is however very seldomly used in normal C DLLs since it is an extra hassle to use Thread Local Storage and most programmers are lazy. 😀 More seriously Thread Local Storage can help with certain specific problems but its usage is very limited and exotic, so chances are pretty small that it is used in any specific DLL. Unless of course you try to call an ActiveX component in your DLL, since they are generally all apartement threaded which explicitly means that they can only work safely if always called from the same thread.

 

LabVIEW's inherent multithreading doesn't guarantee that the different code parts are alway executed in the same thread, unless you force the code into the UI thread. This is the only thread that LabVIEW will never attempt to distribute in any way over multiple threads.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 11 of 26
(1,580 Views)

@charmelony_ wrote:

The vendor said they do not know. I let the Vi work enabling call library running in any thread. It has been two days, and so far there is no crash, all data are saved correctly. There is a case structure which makes dll calls are in sequence. That could be the workaround as you suggested. 

 

I will report again couple days later. I conduct long term experiments and cannot risk any crash. That was the reason that I was hesitate running in any thread. 


I greatly appreciate your efforts to open a conversation with the vendor.  

 

"I do not know. " is an honest answer.  Yet, I have personally been in positions where an honest answer is vastly divergent from a "Nuclear Qualified Answer."  

 

Such answers follow the form of, "I do not know but, I will find out by researching (data store) and get back to you (daily, hourly, weekly, ) with updates."


"Should be" isn't "Is" -Jay
0 Kudos
Message 12 of 26
(1,565 Views)

@rolfk wrote:

 

LabVIEW's inherent multithreading doesn't guarantee that the different code parts are alway executed in the same thread, unless you force the code into the UI thread. This is the only thread that LabVIEW will never attempt to distribute in any way over multiple threads.


Perfectly right!

If we have non-thread-safe DLL, which needs to be called from LabVIEW, then this DLL shall be marked as "Run in UI thread". Obvious disadvantage - we will block UI thread (and UI itself)  as long as we staying inside of this DLL.

 

More that 10 years ago I've dropped a comment here - how is possible to call DLL in same thread, but not in UI using nicompute.dll (which was a part of NI GPU toolkit):

https://forums.ni.com/t5/LabVIEW/Force-DLLs-to-tun-in-the-same-thread-expect-the-UI-Thread/m-p/11454...

 

Technically this could be done also without nicompute. The idea behind is pretty simple and straight forward - we will create wrapper-DLL with own thread, where we will perform the calls of the non-thread-safe DLL.

 

The easiest way is to create this thread on attach of the wrapper dll directly in entry point something like this:
Screenshot 2022-09-14 16.55.10.png

 

Now ThreadProc() function may look like this:

 

Screenshot 2022-09-14 16.56.29.png

Then instead of direct call I will call a wrapper (and this call will be marked as "Run in any thread" of course):

Screenshot 2022-09-14 16.58.43.png

and Execute() is just signalling to ThreadProc to execute where I will call my non-thread-safe function (can be imported function called from other DLL, of course):

 

Screenshot 2022-09-14 16.59.54.png

 

That is. Now on every call we will call our non-thread-safe function in single thread, which is other than UI thread.

If you will run this test VI

Screenshot 2022-09-14 17.02.04.png

 

then you will see that "Run in UI thread" marked calls will be executed in same thread; direct call in "any thread" will be performed sometimes in other thread and you will see thread switches, but call via wrapper will be always in same thread regardless from "run in any thread" setting:

Screenshot 2022-09-14 17.05.06.png

 

I will leave source here, may be will be useful for someone. It is LabVIEW 2022Q3/CVI2020 (yes, I still using CVI time to time).

The code is "quick and dirty", done mostly within my lunch break, but should give you an idea how to deal with threading in LabVIEW.

 

Another possible way it the following:

You can set preferred execution system for your SubVI from which the DLL is called to other, something like that:
Screenshot 2022-09-14 17.19.36.png

 

Now you can set up amount of the threads for this execution system using threadconfig.vi located in C:\Program Files\National Instruments\LabVIEW 2022\vi.lib\Utility\sysinfo.llb (location could be different depends on LabVIEW version and bittness, of course):

Screenshot 2022-09-14 17.22.46.png

 

Then after restart your SubVI (and the DLL inside) will be called always from the same thread. If you will build executable, don't forget to copy according INI-entries  (ESys.other1.Normal=1 and so on) from LabVIEW.ini to your application's ini file. The only thing which may be not good - in the VIs configuration this option called "Preferred execution system", which means that it is not fully guaranteed that this SubVI will be always called here. The way with own thread explained above will give you this guarantee.

 

Sorry for such long and really advanced comment.

 

regards,

Andrey.

Message 13 of 26
(1,560 Views)

Don't apologize for that!  I learned something. 


"Should be" isn't "Is" -Jay
0 Kudos
Message 14 of 26
(1,405 Views)

@JÞB wrote:

Don't apologize for that!  I learned something. 


Very glad to see that this comment was useful for Knight Of NI as well!

0 Kudos
Message 15 of 26
(1,357 Views)

@Andrey_Dmitriev wrote:

Sorry for such long and really advanced comment.

 

regards,

Andrey.


Ironically, that dll was probably made like that to make it thread safe(r). But in LabVIEW, where we don't think (much) about threads, it makes things worse. 

 

I'm not a knight (yet, ~40 posts to go 😮), but after 23 years of programming LabVIEW I still pick up thinks from complete beginners... (You're obviously not a complete beginner).

0 Kudos
Message 16 of 26
(1,341 Views)

wiebe@CARYA wrote:
...but after 23 years of programming LabVIEW I still pick up thinks from complete beginners... (You're obviously not a complete beginner).

No, I'm only 21 years with LabVIEW since 5.1, but still learning.

 

In addition to previous comment, and it seems to be that LabVIEW will allow the only up to 24 parallel threads for DLL calls within one execution system, regardless from thread config.

Here is the statement: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000PARmSAO&l=en-US

and seems to be valid not only for single CPU system.

 

So, my answer to initial question about 48 parallel calls - it seems to be that it is necessary to put DLL calls into two reenterant SubVi, set different execution system for both and call it parallel, then 48 parallels calls will be possible (in case if this library is thread-safe, of course):

Screenshot 2022-09-15 13.23.40.png

Experiments are in attachment.

Andrey.

0 Kudos
Message 17 of 26
(1,335 Views)

Since Andrey pointed out that KB article I feel like I should chime in on the set threadconfig.vi mentioned in the article. 

 

Using that vi changes how your development machine assigns a default thread pool.  It does not change the settings on any target machine you might deploy to.  It also affects every vi on your development machine.  Even ones that worked just fine before.  Don't try that at home unless you REALLY know that you must use it and then, you have @99.999% chance of being wrong.


"Should be" isn't "Is" -Jay
0 Kudos
Message 18 of 26
(1,319 Views)

@JÞB wrote:

Since Andrey pointed out that KB article I feel like I should chime in on the set threadconfig.vi mentioned in the article.

...

Don't try that at home unless you REALLY know that you must use it and then, you have @99.999% chance of being wrong.


This is true. Today I've tried to set single thread for every execution system including standard and got LabVIEW which was unable to start at all, then removed custom config manually from ini file.

 

But I think, author of this question don't need to play with this at all - he wanted to run 48 copies of the same function parallel and need to prove first if this given library is thread safe or not. In general - it is very rare case - in whole my career I've got similar task only once.

0 Kudos
Message 19 of 26
(1,309 Views)

@Andrey_Dmitriev wrote:

But I think, author of this question don't need to play with this at all - he wanted to run 48 copies of the same function parallel and need to prove first if this given library is thread safe or not. In general - it is very rare case - in whole my career I've got similar task only once.


Unless the different flow controllers are all connected over different IO ports, it makes no real sense to call the 48 functions in parallel. The driver hopefully does arbitrate those calls anyways to sequentialize the requests and responses over the shared connection bus. If it doesn't the OP is in for lots of surprises such as wrong values reported for the wrong device and other such nasties.

The problem was mainly that those functions seem to (properly, maybe?) arbitrate, blocking the call for the duration of sending out the command and receiving the response and that being done in the UI thread, monopolizes the LabVIEW environment very much for these IO calls, which for the most time just sit there and wait for the response of the device (if you look at the time spent for sending out the command, waiting for a response and decoding that response, the waiting part usually accounts for 95 to 99% of the time).

By making sure to have the driver monopolize another thread than the UI thread, LabVIEW can stay responsive. But in the case of LabVIEW this usually means that the functions can be called from different threads even if you properly sequentialize them through dataflow. This usually is not a problem, but depending on how the driver was written and what environment was used to write it (Visual Basic DLLs were famous for such things as they relied for many things on ActiveX under the hood) it could be a problem. If you don't properly sequentialize the calls in LabVIEW however, many drivers will sooner or later have trouble.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 20 of 26
(1,283 Views)