I’m currently securing references to the PlayList in my background script. I’m unsure about how broadly to apply BeginUpdate / EndUpdate protection.
I understand the need to use this every time I read/write anything about the list or Items PlayList, such as count, order, metadata, etc.
But what about other references to the PlayList such as when its related classes do actions like playing the Items, such as PlayList(0).GetPlayer(0).Start?
mAirList is “multi-threaded”, which means that multiple parts of the code can run, and access the same objects, at the same time. In particular, scripts run in a thread of their own.
Without proper locking, you are prone to race conditions. Very simple example:
Script determines the number of items in the playlist with GetCount, with a return value of e.g. 20.
Script runs a for loop to modify each of these 20 items.
Now imagine between the first and the second step, or during the first loop, another part of the program removes an item from the playlist, so there are only 19 items now. That will lead to a crash of your script when the loop reaches item #20.
For single-command operations, locking is not necessary normally. But as soon as part of your code relies on things retrieved/peformend in earlier part of your code, you should use locking.
BeginUpdate/EndUpdate will not only lock the object, but also defer all change notifications to the point where you call EndUpdate. So the commands can also be used when you do a huge number of operations and want to prevent (slow) GUI updates in between.
There is also BeginRead/EndRead which only does the locking, but it should only be used for read-only-operations.
And always remember to use a try...finally...end block to make sure that EndUpdate is called even when there is a runtime error in your code.
I’m always adding the try…finally block around the BeginUpdate-EndUpdate calls as you describe. But sometimes an exception is thrown - “Object Lock Not Owned”.
Does that suggest a conflict with some other update lock?
Would the value returned by GetUpdateState be any use here?
This message will only appear if the BeginUpdate/EndUpdate (or BeginRead/EndRead) are not properly balanced, i.e. when you call EndUpdate without a matching BeginUpdate first.
As long as you always use a proper try/finally/end block like this, it should never happen:
Playlist.BeginUpdate;
try
// do some stuff
finally
Playlist.EndUpdate;
end;
(Replace Playlist with whatever object you are accessing.)
The finally part will always be executed, even if your code exits prematurely, e.g. using exit or due to a runtime error.