In the beginning argv will point to argv[0] which is the executable file name, it's increased once inside while() to point to argv[1].
Now it hits fork() creating a second thread starting at the same line.
Both threads will write a to their own stdout buffer.
Now argv is moved by 1 character in both instances (inside while()), as they essentially work with copies if I remember that correctly.
The fork in each thread will now create 2 additional copies of the thread (one for each existing thread).
Now the 4 instances will all have the 'a ' still in their stdout buffer that is copied (think so, would be nice if anyone could confirm this) and their argv pointing to b. This one is written as well, so now we've got 4 threads each having 'a b ' in their output buffers.
Once they end, their buffers are flushed resulting in the 'a b a b a b a b ' (essentially being 'a b ', 'a b ', 'a b ', and 'a b ').
Ben's comment can be explained by flushing caused by the linebreaks.