You have a race condition (i.e. you do not have the implied safety of the stdio stream).
The problem is even more serious. You may receive duplicate "func" messages.
The problem is that using clone does not have the same guarantees as pthread_create . (i.e. you will not get printf safe flow options.
I do not know for sure, but, IMO, the phrase about stdio threads and thread safety, in practice, applies only when using pthreads .
So you have to handle your own interthread lock.
Here is the version of your program transcoded to use pthread_create . It seems to work without incident:
#define _GNU_SOURCE #include <sched.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #include <time.h> #include <pthread.h> #define STACK_SIZE 1024*1024 void *func(void* param) { printf("I am func, pid %d\n", getpid()); return (void *) 0; } int main(int argc, char const *argv[]) { printf("I am main, pid %d\n", getpid()); void* ptr = malloc(STACK_SIZE); printf("I am calling clone\n"); pthread_t tid; pthread_create(&tid,NULL,func,NULL); //int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL); int res = 0; // works fine with sleep() call // sleep(1); if (res == -1) { printf("clone error: %d", errno); } else { printf("I created child with pid: %d\n", res); } pthread_join(tid,NULL); printf("Main done, pid %d\n", getpid()); return 0; }
Here is a test script that I used to check for errors [it's a little rude, but should be fine). Run against your version and it will be interrupted quickly. The pthread_create version seems to go just fine
#!/usr/bin/perl # clonetest -- clone test # # arguments: # "-p0" -- suppress check for duplicate parent messages # "-c0" -- suppress check for duplicate child messages # 1 -- base name for program to test (eg for xyz.c, use xyz) # 2 -- [optional] number of test iterations (DEFAULT: 100000) master(@ARGV); exit(0); # master -- master control sub master { my(@argv) = @_; my($arg,$sym); while (1) { $arg = $argv[0]; last unless (defined($arg)); last unless ($arg =~ s/^-(.)//); $sym = $1; shift(@argv); $arg = 1 if ($arg eq ""); $arg += 0; ${"opt_$sym"} = $arg; } $opt_p //= 1; $opt_c //= 1; printf("clonetest: p=%dc=%d\n",$opt_p,$opt_c); $xfile = shift(@argv); $xfile //= "clone1"; printf("clonetest: xfile='%s'\n",$xfile); $itermax = shift(@argv); $itermax //= 100000; $itermax += 0; printf("clonetest: itermax=%d\n",$itermax); system("cc -o $xfile -O2 $xfile.c -lpthread"); $code = $? >> 8; die("master: compile error\n") if ($code); $logf = "/tmp/log"; for ($iter = 1; $iter <= $itermax; ++$iter) { printf("iter: %d\n",$iter) if ($opt_v); dotest($iter); } } # dotest -- perform single test sub dotest { my($iter) = @_; my($parcnt,$cldcnt); my($xfsrc,$bf); system("./$xfile > $logf"); open($xfsrc,"<$logf") or die("dotest: unable to open '$logf' -- $!\n"); while ($bf = <$xfsrc>) { chomp($bf); if ($opt_p) { while ($bf =~ /created/g) { ++$parcnt; } } if ($opt_c) { while ($bf =~ /func/g) { ++$cldcnt; } } } close($xfsrc); if (($parcnt > 1) or ($cldcnt > 1)) { printf("dotest: fail on %d -- parcnt=%d cldcnt=%d\n", $iter,$parcnt,$cldcnt); system("cat $logf"); exit(1); } }
UPDATE:
Could you recreate the problem with OPs with clone?
That's right. Before I created the pthreads version, in addition to testing the original version of OP, I also created versions that:
(1) added setlinebuf to the start of main
(2) added fflush just before clone and __fpurge as the first func statement
(3) added fflush to func before return 0
Version (2) eliminated duplicate parent messages, but duplicate child messages remained
If you want to do this, download the OP version from the question, my version and test script. Then run the test script in the OP version.
I have posted enough information and files so that everyone can recreate the problem.
Please note that due to the differences between my system and the OP, I could not first reproduce the problem in just 3-4 attempts. So why I created a script.
The script executes 100,000 test runs, and usually the problem will manifest itself within 5000-15000.