I wrote some thread code with what seems like the wrong assumption that integers were thread safe. Now it seems that, although they are, my use of them is NOT thread safe. I use a global ThreadCount integer to store the number of threads. During thread creation, I increase ThreadCount. During the destruction of the stream, I reduce it. After all threads are created, I wait for them to execute (ThreadCount should drop to 0), and then write my final report and exit.
Sometimes (5%), although I never get 0, although a post-mortem study of my journal shows that all threads were running and ending. Thus, all signs point to a totalization of ThreadCount. I told myself that this is not possible since it is an integer and I just use inc / dec.
Here is the code:
var // global ThreadCount : integer; // Number of active threads ... constructor TTiesUpsertThread.Create(const CmdStr : string); begin inherited create(false); Self.FreeOnTerminate := true; ... Inc(ThreadCount); // Number of threads created. Used for throttling. end; destructor TTiesUpsertThread.Destroy; begin inherited destroy; Dec(ThreadCount); // When it reaches 0, the overall job is done. end; ... //down at the end of the main routine: while (ThreadCount > 0) do // Sometimes this doesn't ever end. begin SpinWheels('.'); // sleeps for 1000ms and writes dots... to console end;
I THINK that my problem is with inc / dec. I think I get collisions when two or more dec () hit at the same time and both read the same value, so they replace it with the same value. ex: ThreadCount = 5, and two threads terminate simultaneously, both are read 5, replaced by 4. But the new value should be 3.
This never encounters difficulties in our test environment (other equipment, topology, loading, etc.), so I am looking for confirmation that this is probably a problem before I try to โsellโ this solution for a business unit.
If this is my problem, am I using critical selection to protect inc / dec?
Thanks for watching.
source share