Consider the following piece of code running under Solaris 11.3:
void *run(void *args) {
int i;
for (i = 0; i < 100; i++) {
printf("Line #%d printed by child\n", i + 1);
}
}
int main() {
pthread_t tid;
int ret = pthread_create(&tid, NULL, run, NULL);
int i;
for (i = 0; i < 100; i++) {
printf("Line #%d printed by parent\n", i + 1);
}
pthread_exit(NULL);
}
Upon running, the parent thread always prints out all of its lines before the newly created thread. Some might say that pthread_create
is just too slow to allow the other thread to even start its job before the main thread returns. However, swapping out printf
for write(2)
produces
the expected output where the threads occasionally take turns printing their lines.
How could this behaviour be explained?
Buffering certainly has nothing to do with it since terminal output is line-buffered by default; it should be true for both write
and printf
.
Even if the functions use some sort of a blocking techique to provide thread-safety, what exactly would prevent the output from scrambling?
It is eniterly due to speed. If you put a call to usleep
between the pthread_create
and the loop, and tune the value a bit, you can get it to mix some of the lines.
Note that due to stdio locking, once one thread fails to acquire the lock on stdout
once or twice, it is likely to sleep for a few milliseconds (which will allow the other thread to complete its loop), so you won't see a lot of mixing. If you want more mixing, you'll need to put a usleep
in the loop too.
On my machine a usleep(50)
before the loop in the parent, and a usleep(1)
in both loops will result in almost alternating lines.