Heteroclinic.net logo

www.heteroclinic.net

Concurrency Basics:
I. A Tutor's Homework
To write multi-threading program could be quite challenging. But to write server program or at least to understand how server programs are working, it is worth spending some effort. We imagine a case supposed to be the simplest. Or say, if I am the tutor of COMP 2xx (probably 3xx, 4xx or something after operating system in most schools), I will use this example. The requirement is as the following:

- start a given number of threads

- each thread execute a radom long task, ranging from ll (lower limit) to ul (upper limit) slices, both inclusive. Each slice of time is atomic, the task can only be terminated between two slices. To simplify this requirement, we just increase an integer and let the thread sleep the same duration as the slice.

- at the beginning of each thread, the task duration set prepresented by the number of slices will be printed to standard output.
- each thread/task may be termininated prematurely, so we use a condition variable 'halted' to control each thread.

- at the end of each task, print the progress of the task, complete or partially completed, shown as the integer number of slices.

This requirement has already been quite technical, like a programmer talking to a programmer, suppose they are nice to each other. In this sense, the simple-ness is compared to the real-life human language. Real-life language can request ``I want to put the customers to three categories: children, woman and man''. But I do believe most programmers would prefer to say ``1. children, male or female under the age 18. 2. male above 18. 3. female above 18.'' An immediate thought jumped to mind is that there will be an exception at the 18th birthday of someone. ``So could you please be more specific?'' A programmer could think quite different even odd. But it is the way to talk to compiler and database system.

Let's come back to our example. After some hours' sourcing, coding, we come to a segment of code. I use Visual C++ 2010 Express. I use Microsoft Windows native threading library, namely Windows.h. I don't have any preference of compilers or operating system. My principle is to solve problems with the minimum cost. That is, the problem should be solved by the mothodology, the tools at hand, not the ideology, or personal beliefs. We discuss the beginning code as the next section.

Concurrency Basics:
II. An Early Submission
I thought the requirements are reasonable, implementable, I save the word simple. I review the code several times. I am sure it is going to do what it is supposed to do. You even may say I wrote the requirements after the code is written. So I decide to submit the answer sheet.

Concurrency Basics:
III. Something Went Wrong
First, let's see the requirement ``at the beginning of each thread, the task duration set prepresented by the number of slices will be printed to standard output.'' And the result

Is it fine? Check again. It happened for me spending a decent time to format the output to c++ ostream. So at the first glance, I know there is something going wrong with '01: 366'. If you don't specify the padding, alignment etc, it will not happen such '01' occurs. When this code is ported to another machine, the result is even more messy.

My first suspicion is that for this C++ style code, I should not use native Microsoft Windows threading library. HANDLE, CreateThread should be something managed, or should I do it in the `.net' way. The situation is that typically you get those precious helpful example code for some very paticular problems from the open source community, but your application is dependent on Windows platform.

While, it did not take long for me to figure out that std::cout is a shared resource among the threads. It is not a thread-safe ADT instance.
Concurrency Basics:
IV. A Quick Fix
It was reported, in a very rare situation, some customer received a bill with an astronaumical figure, maybe positive maybe negative. The DBA swears innocently the database is all-right, the accountant, sales representative ... Is it just because two threads try to access a same stringstream concurrently without synchronization? While this is not something for us to conjecture, or to be concerned. But, we met a similar situation. We know statistics, it is just NOT rare.

We would modify our simple example accordingly.