When you start programming with threading, you may start into some wonderful constructs known as non-blocking (or lock-free) containers. These data structures promise to give your threads free reign, running at unfettered speed, without stopping to wait on anything else in your program. However, you can't do a lock-free list on typical CPUs (including x86); you can only do a fixed-size stack lock-free (and even so, it's not safe for arbitrary reading and writing at the same time); you CAN do a fixed-size queue lock-free (known as a non-blocking FIFO). However, in the end, the threads will end up having to wait on SOMETHING. That something might be user input, or the advancement of time. Thus, every thread needs at least one blocking operation per loop. For the main thread, it'll be the message pump; for a worker thread, it'll be the queue of work items. Note that function statics are NOT thread safe. If you're using them, you have to make sure to make initialization safe, or take them out.
Note that if the first call to accessor() overlaps with the second call (on two different threads), one of them may return a reference to a not-yet-initialized object, or the object may be initialized twice, depending on compiler runtime implementation. The only work-around is to use a specific critical section:
This construct will make sure that:
It has the draw-back that two objects can't be initialized at the same time, but that's seldom an actual problem -- initialization is not on the inner-loop performance path. When it comes to threading, there are a few concepts you really need to understand:
If you go to a decent computer science program in college, they will teach you these things; any textbook on operating systems will also cover the area. I suggest you get one and read it if you're going to be doing significant programming with threads. |
|