BACnet icon indicating copy to clipboard operation
BACnet copied to clipboard

BACnetClient is not thread safe

Open sylfab opened this issue 5 years ago • 6 comments

I have two threads in a same program, each thread is executed every seconds, they call ReadPropertyRequest function. First thread get a BinaryValue (0 or 1), second thread get an AnalogValue (between 20 and 30). Sometimes ReadPropertyRequest of BinaryValue return the AnalogValue! Can someone have a solution of my problem? PS: i call ReadPropertyRequest because COV does'nt seem to work for me

sylfab avatar Jul 01 '19 08:07 sylfab

Hi Guys, I have same problem with https://github.com/ela-compil/BACnet/tree/v2-netstandard brunch. Could you please try to fix?

minzdrav avatar Jul 30 '20 09:07 minzdrav

Unfortunatelly the client was not written to be thread safe. Try using a lock each time before you use it or write a wrapper that would do it for you for each atomic operation. Since BACnet operations have identifiers it should be possible to allow multiple requests to be sent out in the same time. I will leave this issue open to try to address it in the future.

gralin avatar Jul 30 '20 10:07 gralin

Hi @gralin Thank you. Yes, it's working fine with locks. I have 1 thread per device and customer want to read properties and values from many devices. I'll try to create BACnet client per thread. Should work faster than locks.

minzdrav avatar Jul 30 '20 10:07 minzdrav

Hey @minzdrav, just wondering if that worked for you? Did you manage to run a client per thread without issue?

MatthijsvdVeer avatar Nov 25 '20 09:11 MatthijsvdVeer

Hey @minzdrav, just wondering if that worked for you? Did you manage to run a client per thread without issue?

Hi @MatthijsvdVeer Yes.

minzdrav avatar Nov 25 '20 09:11 minzdrav

Yup, can confirm the reads are not threadsafe. It has to do with InvokeId, a uint8 that gets added to every request like a correlation ID, it gets incremented every request, and if you send too many requests it can quickly roll over and cause problems.

Update: On further investigation the reads cause a thread to be blocked waiting for reply because of the use of ManualResetEvent, this is actually a much bigger problem, as the non thread-safe client can be wrapped in a mutex, and multiple clients started in parallel, however, the reads will quickly eat up worker threads.

Fortunately a solution could be to replace ManualResetEvent with a TaskCompletionSource which doesn't block a thread. The rest of the code seems to be non-blocking which is great.

YarekTyshchenko avatar Oct 31 '22 08:10 YarekTyshchenko