Skip to main content
14-Alexandrite
September 2, 2019
Solved

Concurrency / Synchronisation / ConcurrentModificationException

  • September 2, 2019
  • 1 reply
  • 8974 views

Hi everybody,

 

Thingworx for sure supports concurrency. I quite often see all the different Thread IDs in the Script Log.

But I reached a point in Thingworx Script Development where I get concurrent conflicts and race conditions. Where are the synchronisation primitives to handle this?

 

The use case:

We have continous running machine providing it's data to twx via the KepServer. Tags of main interest are running meter, speed and timestamps of certain events. 

Now we want to do some aggregation in memory and so I implemented an info table as property of the thing and a timer that frequently calls a service that just accumulates the total meters and the time to the last row of the infotable.

 

For certain events (e.g. change of reel) we now need to create a new row in the infotable and now I run into trouble, as the service to accumulate and the events leading to a new row are not on the same thread.

This lead to synchronisation issues, why I implemented a second infotable as a queue where the events are just stored. Afterwards the timer checks the queue for new rows and creates them. So now creation of row and the accumulation are on the same thread again. Should be OK, ... but it is not. I still get "ConcurrentModificationException".

 

The test/challange:

I found an article here that gave me some info on this issue:

https://community.ptc.com/t5/ThingWorx-Developers/Concurrency/m-p/502299

"To get a lock you need to update a persistent property, if you update a persistent no one will update that Thing until the service you are it's done."

 

With this information I did a quite brutal test (see attached Thing):

  • This thing has a persistant and a not persistant property of type Integer.
  • The service IncrementCounterAsyn increments both properties, first the persisted one.
  • Between the two increments it calls a passive wait "pause(100)" which still should leave the thing locked
  • The service ConcurrentIncrementCounter call the service IncrementCounterAsync 100 times in a loop.
  • Waits for 2 Seconds and than returns the CounterValues ..

As the access to CounterMtx should lock the Thing all the async services should not be finished after 2 Sek. But they are ?

The final result for Counter & CounterMtx should be 100, but it never is. Indeed this is a "nice" random number generator. 😉

 

The question:

Ok how can I lock the Thing, that the final result is 100 for both Counter and CounterMtx??

I know that this test is quite stupid, but it's usefull to show and reproduce the issue.

 

 

 

Best answer by seanccc

Hello @atondorf ,

 

I had created a similar JAVA  extension using the ReentrantLock as well,  yes , it works locally and works for updating Thingworx's persistent property concurrently as well.   But  it doesn't work for updating ThingWorx DataTable concurrently.  

For example,  a DataTable which has several fields named : PropA, PropB , PropC .... PropG.   Now multiple requests update the DataTable simultaneously,  requestA updates PropA,  requestB updates PropB ..... .  The code would be : 

me.lock();

try{
 var entry = 
 me.FindDataTableEntries({
 values: query_value /* INFOTABLE */
 });
 
 //update certain Prop* field 

 me.UpdateDataTableEntry({
 tags: undefined /* TAGS */,
 location: undefined /* LOCATION */,
 source: undefined /* STRING */,
 sourceType: undefined /* STRING */,
 values: station1Clone /* INFOTABLE */
 }); 

}catch(err){
 logger.debug(err);
}finally{
 me.unlock();
}

The expected result would be the PropA ... PropG get updated with new value , but actually only some of the fields get updated . 

 

I also tried your code and got the same inconsistent result . 

 

You can try the attached file to reproduce it : 

1. Run ResetTestData  to reset the test data. 

2. Run ConCurrentUpdateWithoutQuery to call async services to simulate the concurrent requests. 

3. Check the table entry whose key = station1,  you'll see only some of the Prop* field get updated with new value new_xxx. 

 

If you check the log, you'll find these async  services do get executed sequentially.  So I guess  either FindDataTableEntries read from certain old cache, or UpdateDataTableEntry is async somehow. 

 

1 reply

16-Pearl
September 5, 2019

Hi atondorf,

 

I don't think that a persisted property can be used as a mutex.

 

You may want to have a look at the Extension SDK. I have seen in the past Custom Java Extensions for "Concurrent Queue", "Atomic" properties and other "Lock" Things ....

 

atondorf14-AlexandriteAuthor
14-Alexandrite
September 6, 2019

Hi @smainente,

 

a look at the Extension-SDK sounds great! I already searched a lot, but did not find a lot extensions with source code. Even GitHub has only 44 projects with java code for thingworx. No concurrenct extension therer.

And as I am not a great Java-Dev and SDK Documentation is only very rudimentary I do not dare to implement this by myself, yet. Any Tipp where you saw these concurrenct extensions?

16-Pearl
September 6, 2019

Hi @atondorf 

 

A customers and/or consultants probably sent me those extensions - I'm pretty sure they are not public.

 

Alternatively, if you want to do in-memory calculations of ingested data, you may want to have a look at How can I use statistical transforms for my property values in ThingWorx ? - this feature requires ThingWorx Analytics.