Let's talk about theory a bit. We have one container, let's call it TMyObj that looks like this:
struct TMyObj{
bool bUpdated;
bool bUnderUpdate;
}
Let a class named TMyClass have an array of the container above + 3 helpful functions. One for getting an object to be updated. One for adding update info to a certain object and one for getting an updated object. It's also called in this order. Here's the class
class TMyClass{
TmyObj entries[];
TMyObj GetObjToUpdate;
{
//Enter critical section
for(int i=0; i<Length(entries); i++)
if(!entries[i].bUnderUpdate)
{
entries[i].bUnderUpdate=true;
return entries[i];
}
//Leave critical section
}
//the parameter here is always contained in the Entries array above
void AddUpdateInfo(TMyObj obj)
{
//Do something...
//Enter critical section
if(updateInfoOver) obj.bUpdated=true; //left bUnderUpdate as true so it doesn't bother us
//Leave critical section
}
TmyObj GetUpdatedObj
{
//<-------- here
for(int i=0; i<Length(entrues); i++)
if(entries[i].bUpdated) then return entries[i];
//<-------- and here?
}
}
Now imagine 5+ threads using the first two and another one for using the last function(getUpdadtedObj) on one instance of the class above.
Question: Will it be thread-safe if there's no critical section in the last function?
Given your sample code, it appears that it would be thread-safe for a read. This is assuming entries[]
is a fixed size. If you are simply iterating over a fixed collection, there is no reason that the size of the collection should be modified, therefore making a thread-safe read ok.
The only thing I could see is that the result might be out of date. The problem comes from a call to GetUpdatedObj
-- Thread A
might not see an update to entries[0]
during the life-cycle of
for(int i=0; i<Length(entrues); i++)
if(entries[i].bUpdated) then return entries[i];
if Thread B
comes along and updates entries[0]
while i > 0
-- it all depends if that is considered acceptable or not.