Writing a unit test for a singleton implementation

Idan Arye GenericNPC at gmail.com
Fri May 17 16:02:13 PDT 2013


On Friday, 17 May 2013 at 21:06:30 UTC, Diggory wrote:
> I think we all understand it's not going to catch every race 
> condition, or even a given race condition every time, ie. it 
> can't prove that the code is correct.
>
> What it can do however is prove that code is incorrect. If the 
> unit test fails there is definitely something wrong with the 
> code, therefore it's a useful test to have.
>
> The most obvious case is if there is a change to the singleton 
> code which accidentally creates a race condition. Any chance of 
> detecting that in a unit test is better than no chance of 
> detecting it.

Exactly!

Anyways, I've updated the gist with an even better solution, that 
gave me 100% accuracy even when playing 4 video files.

I added a static shared counter that counts how many threads have 
passed the barrier - every thread has to increment it immediately 
after it passes the barrier. The constructor, instead of a single 
call to `sleep()`, calls `sleep()` until the counter reaches the 
number of threads. So, this is what happens:

1) 10 threads are started, each stops at the barrier waiting for 
the others.
2) Once all the threads have reached the barrier, threads are 
starting to get released(from the barrier, not from memory).
3) Each thread released from the barrier increments the counter.
4) At least one thread passes the singleton checks, enters the 
constructor and goes into a loop where it calls `sleep()` all of 
the threads got a chance to run again.
6) Once all the threads got that chance, all the threads stuck in 
the constructor get released from the loop.

Now, theoretically this unit test is not 100% accurate. If all 
the threads except one get switched out between step 3 and step 4 
- that is, after they increment the counter but before they pass 
the singleton checks - then by the time those threads will run 
again, the one other thread gets to initiate the singleton and 
write the __gshared instance field - which means the other 
threads won't pass the singleton checks and won't create more 
instances, and the unit test won't fail even if the 
implementation is broken.

Now, while theoretically possible, this scenario is far fetched 
in reality. The window where a thread needs to be switched is 
very short, and placed immediately after it gets switched in. The 
amount of work the thread does in that window after it got 
switched in is smaller(or at least not much larger) than the work 
needed for the context switch, so no sane operation system should 
switch it out in that window - let alone switch out nine such 
threads.


More information about the Digitalmars-d mailing list