Oops. When I upgraded my test, I added my standard shift-register database, but forgot to add the read-for-write VI. It is separate from the data VI due to deadlock problems. You can't wait in the data VI, since the data VI cannot be reentrant. The attached file contains the fixed VIs. Unzip into the Shift Register directory. Strangely enough, using the same conditions, I got faster speeds when I actually acquired the semaphore like I should have. Once again, Pentium 4, 2.4GHz HT, 512MBytes RAM, 10,000 iterations.
Shift Register - 462ms
This is probably because the semaphore did not have to go through a lot of error code when it attempted to release a non-acquired flag.
I agree that locking data when reading preparatory to writing is very important to prevent race conditions. The queue methodology does this for you if you follow two simple guidelines. First, the queue size has to be set to one element. Second, all operations on the data start with a dequeue. So, an isolated read-for-write would be a simple dequeue. The queue is now empty. If another part of the program wishes to access the data, they start with a dequeue. The queue is empty, so they wait until the write enqueues the data. I find this approach simpler and more elegant than using semaphores. The fact that it is much faster and memory performance is superior is even better.
I would also like to second your comment that GOOP does not replace globals, it allows you to avoid them. Many of the problems LabVIEW developers face would never occur if they used object-oriented design techniques. The databases in the test can all be used as the core for this development. Unfortunately (or fortunately for Endevo), only GOOP2 has inheritance...