Data Collision Handling - Different Concurrent Tasks Accessing the Same Array

130 views
Skip to first unread message

Cindy

unread,
May 20, 2014, 1:47:41 PM5/20/14
to tas...@googlegroups.com

I have different/multiple concurrent tasks that write to the same array of data while a webview's javascript reads the data. Looking at the log it appears that my app can lock up when data collision occurs. Does Tasker provide any functions like a critical section to protect/lock sections of code that could be contending for the same data? My thought is to create a DataLock task that locks/waits for critical sections of code to execute so that only one task updates the array at a time.  See Below:

 

Task: DataLock (1065)

            A1: Wait Until [ MS:250 Seconds:0 Minutes:0 Hours:0 Days:0 ] If [ %GXDataLock ~ false ]

            A2: Variable Set [ Name:%GXDataLock To:true Do Maths:Off Append:Off ] 

            *Note: Collision Handling = "Run Both Together"

 

Task: DataUnLock (1066)

            A1: Variable Set [ Name:%GXDataLock To:false Do Maths:Off Append:Off ] 

 

Both DataLock and DataUnLock would need the priority set to the same level, i.e. 10.

 

Calling it would look something like this:

UpdateArrayTask1 - Background task

     DataLock true

     Do Something with the array

     DataLock false

 

UpdateArrayTask2 - Foreground task (called from the webviews Javascript, i.e change the spelling of a name) 

     DataLock true

     Do Something with the array

     DataLock false

 

ReadArray - Webview task (gets data, refreshes screen if name spelling changed...)

     DataLock true

     Read the array

     DataLock false

 

This way only one Task would be able to lock the code and update the data, the other task would wait its turn until the unlock is called. I really don't care which task executes first. I just don't want to abort any tasks because it could get confusing for the user. For example if the user changes an array element at the same time Tasker is updating the status of the same element - choosing which one to abort is messy.

 

Is there a better way?

 

Cindy



easiuser

unread,
May 20, 2014, 3:07:42 PM5/20/14
to tas...@googlegroups.com
It depends on what your array looks like but you may try to que up requests and process them in turn by a single task.  It would look something like this:
 
 
All the tasks that want to change the array (%Data) would prepend a command to the data and push the request into a separate array (%Que) and then continue on, return or whatever.  Since I assume Tasker will not swap tasks in the middle of a single action, there should be no conflict with different tasks adding to the %Que.
 
A separate profile is triggered whenever %Que is set.  Enforce Task Order to prevent multiple instances running. This profile would pop the last item off the array and then make the changes to %Data.  It would loop back and continue to process the last item until %Que is empty.  Note it may not be empty if another task added a request to %Que while processing the current one.  This way only one task is changing the %Data.
 
As for reading the data.  Copy it to a local array to get a current snapshot of %Data and display as desired.  You could check and wait until the processing task (via %TRUN) is not running if you want to make sure that %Data is up to date befire copying.
 
Examples:
 

UpdateArrayTask1 - Background task

Array Push %Que,1,Add|New record to be added to the array
UpdateArrayTask2 - Backgound task

Array Push %Que,1,Delete|Data to update the array

 
UpdateArrayTask2 - Foreground task (called from the webviews Javascript, i.e change the spelling of a name)
Array Push %Que,1,Update|Data to update the array
Create a profile that will be active whenever %UpdateQue is set
Stop if %Que(#) = 0
Array Pop %Que, %Que(#)) to %buffer,                         (get the last item in the que, ie first one in)
Process the %buffer contents to update %Data             (parse %buffer and perform the opration you want on %Data)
goto 1                                                                              (check for more)
 
ReadArray
Varable set %Array to %localarray                                 (copy the array to a local variable to get a current snapshot of the array
 
I do something very similar to process my new texts and emails so I do not miss them when the come in right after each other.  When one arrives I push it into a que (ie one statement) so it can catch the next one.  The separate profile displays them, gives me a chance to respond and other options.  When complete, it processes the next message in the que if there is one.

Cindy

unread,
May 20, 2014, 3:20:39 PM5/20/14
to tas...@googlegroups.com
Nice, I really like your solution! 

How could you ensure that user interaction requests are handled first so that the app doesn't appear sluggish.  My fear would be that if the task is added to beginning of the que then there could be another read/write contention issue.  If its added to the end then there shouldn't be a data contention issue but the app could appear sluggish/slow while user interaction tasks wait for execution behind other slower queued tasks.

Cindy

easiuser

unread,
May 20, 2014, 5:59:05 PM5/20/14
to tas...@googlegroups.com
You will probably still be ok because all interactions with the queue are completed in 1 action.  You are either pushing something into the queue or popping it off.  There are no partial operations that a task could be in the middle of when another process changes the queue.  According to the user guide:
 

Array Push

Add a new element to a variable array, pushing existing elements upwards to make space if necessary.

If Position is higher than the last index in the array, the new element is added at the end of the array.
So to put a high priority task in the queue, select a real high position or maybe 10 higher than the last element, then the element will be placed on the end of the array regardless of how many have been added.
 
One note:  You cannot put %Que(#)  in the position of an Array Pop or Push action.  You will have to do a Variable Set %last to %Que(#) and use that in your Array Pop action.  If another routine happens to push something on the end between the Variable Set and Array Pop actions you should still be ok.  You will just get the next to the last item, everything will shift down and it will be the last item when you loop back.

Pent

unread,
May 21, 2014, 2:11:21 AM5/21/14
to tas...@googlegroups.com

I have different/multiple concurrent tasks that write to the same array of data while a webview's javascript reads the data. Looking at the log it appears that my app can lock up when data collision occurs.


I'm not sure (exactly) what you mean by data collision.

Could you paste in or describe the bit of log that leads you to that conclusion ?

Thanks,

Pent
Reply all
Reply to author
Forward
0 new messages