0

I'm writing a C program using Pthreads that creates a child thread. After creating the child thread, the parent thread should ouput two messages: "parent:begin" then it should print "parent:done". Same for child thread "child:begin" and "child:done". I have to make sure that the main thread prints his second message before the spawned (child) thread does. I have to following implementation but it only prints in the wrong order. I assume I should use flags. Any help would be appreciated.

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>


volatile int done = 0;

void *child(void *arg) {
 printf("child\n");
done = 1;
 printf("child:done");
return NULL;
 }

int main(int argc, char *argv[]) {
 printf("parent: begin\n");
 pthread_t c;
 pthread_create(&c, NULL, child, NULL); // create child
 while (done == 0); // spin
 printf("parent: end\n");
 return 0;
 }
Le Coder
  • 79
  • 1
  • 7
  • Your child thread only emits one message. – uselpa Jan 31 '16 at 20:54
  • A better way of doing this is with the [`wait`](http://linux.die.net/man/2/wait) family of system calls instead of a busy loop in the parent. – kaylum Jan 31 '16 at 20:56
  • Thank you, I have updated the code, and what I would like to achieve is to make sure that the main thread prints his second message before the spawned (child) thread does. – Le Coder Jan 31 '16 at 20:57
  • at the moment: 1. parent:begin 2.child 3.child:done 4.parent:end. – Le Coder Jan 31 '16 at 21:01

2 Answers2

2

If you want the parent to print done first, then you should have the child thread spin until the parent is done. (Right now the parent spins waiting for the child.) You should also use pthread_join to make sure the child is done before the main thread returns:

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>


volatile int done = 0;

void *child(void *arg) {
    printf("child: begin\n");
    while (done == 0); // spin
    printf("child: done\n");
    return NULL;
}

int main(int argc, char *argv[]) {
    printf("parent: begin\n");
    pthread_t c;
    pthread_create(&c, NULL, child, NULL); // create child
    printf("parent: done\n");
    done = 1;
    pthread_join(c, NULL);
    return 0;
}

On my machine I get this output:

parent: begin
parent: done
child: begin
child: done
DaoWen
  • 32,589
  • 6
  • 74
  • 101
  • 1
    This doesn't guarantee that child:begin won't be printed before parent:done. – 2501 Jan 31 '16 at 21:12
  • 1
    @2501 - That's true, but based on the criteria in the question I think only the "done" part matters...? If the "child: begin" messages also need to be ordered, then `printf("child: begin\n");` should be moved after the spin loop. – DaoWen Jan 31 '16 at 21:15
  • 1
    Even if this was the desired output order (not quite clear from OP's Q and comment), the program is still wrong since it contains *data race* which yields *undefined behaviour*. Because `done` is being accessed by both threads without any lock. – P.P Jan 31 '16 at 21:33
  • @l3x - I agree that this probably isn't the most correct solution (I would have preferred to use atomics instead), but it's simple, should work on most platforms (the compiler/hardware would really have to go out of its way to screw this one up), and anything more complex would probably be outside the scope of the assignment (I'm assuming this is homework). However, I still feel I should point out that your comment is not very useful because you don't say *in terms of what* the behavior is undefined. Undefined for POSIX? C11? (Pedants should be precise!) – DaoWen Jan 31 '16 at 23:25
  • @DaoWen You might as well argue that `i = i++ + i--;` "should work" and produce a certain output on most systems. Pointing out *data race* (undefined behaviour) is NOT a pedantic comment. POSIX doesn't explicitly say it but a program with data race can't be anything but invalid. C11 says it's *undefined*. – P.P Jan 31 '16 at 23:56
0

At the moment done is accessed without any synchronization by both threads. Proper way is to signal the child that the parent has completed printing using a conditional variable. This leads to data race.

Moreover, main() thread complete the execution before the does. In that case, the whole process will die. You can either call pthread_join() or simply exit the main thread with pthread_exit().

    #include <unistd.h>
    #include <stdio.h>
    #include <pthread.h>

    pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
    pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

    volatile int done = 0;

    void *child(void *arg) {
      printf("child\n");
      pthread_mutex_lock(&mutex);
      while(done == 0)
        pthread_cond_wait(&cond, &mutex);

      pthread_mutex_unlock(&mutex);
      printf("child:done");
      return NULL;
   }

    int main(int argc, char *argv[]) {
      printf("parent: begin\n");
      pthread_t c;
      pthread_create(&c, NULL, child, NULL); // create child

      pthread_mutex_lock(&mutex);
      done = 1;
      printf("parent: end\n");
      pthread_cond_signal(&cond);
      pthread_mutex_unlock(&mutex);

      pthread_exit(0);
   }
P.P
  • 117,907
  • 20
  • 175
  • 238
  • The question is ambiguous, so I guess it doesn't matter. – 2501 Jan 31 '16 at 21:20
  • @2501 `I have to make sure that the main thread prints his second message before the spawned (child) thread does` <-- This, as I understand, says `parent:end` (2nd msg) gets printed first *before* `child:done` gets printed. `at the moment: 1. parent:begin 2.child 3.child:done 4.parent:end.` <-- OP considers this as wrong output since `parent:end` gets printed as last. But OP obviously accepted an answer which produces something different which disagrees with my interpretation. – P.P Jan 31 '16 at 21:34
  • Isn't it sad that we must debate what OP what thinking about, when he refuses to respond to my (now deleted) comments to clarify the question. I usually hit close/downvote and I think that is the correct response if OP doesn't respond. – 2501 Jan 31 '16 at 21:47
  • OP was busy. First, thank you for your respond @2501. To make it clear i write it here: I have to implement it so that the main thread prints his second message before the spawned thread does his second message. thank you. – Le Coder Jan 31 '16 at 22:34