starkk92
starkk92

Reputation: 5924

Flow of program execution during Thread creation

I am new to threads.

I have written a sample program to create a thread.

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include<string.h>
#include<pthread.h>


void * func(void * temp)
{
    printf("inside function\n");
    return NULL;
}

int main()
{
    pthread_t pt1;
    printf("creating thread\n");
    pthread_create(&pt1,NULL,&func,NULL);
    printf("inside main created thread\n");

return 0;
}

After compilation the answer is found to be :

creating thread
inside main created thread
inside function
inside function

I understand that answer may vary as return 0; may be called before the printf in func is executed. But how come in the solution, inside function is printed two times?

On compiling With gcc -o temp thread1.c -lpthread on first run:

creating thread
inside main created thread

on second run:

creating thread
inside main created thread
inside function
inside function

On compiling with gcc -pthread -o temp thread1.c On first run:

creating thread
inside main created thread
inside function
inside function

I have observed this behavior on

gcc version: 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
Kernel release:2.6.32-24-generic
glib version:2.11.1

Upvotes: 8

Views: 985

Answers (4)

ov2k
ov2k

Reputation: 415

I can't comment, but there are several duplicate questions with more informative answers. A glibc bug is likely the cause of the unexpected behavior, and as noted in other answers, pthread_exit and pthread_join are suggested workarounds.

Upvotes: 0

Don Shankin
Don Shankin

Reputation: 440

For starters, as far as I can remember, compiling with "-pthread" is equivalent to compiling with "-D_REENTRANT -lpthread", so that's the only difference there. Note that printf and the like are not reentrant because they operate on a global buffer.

Having said that, I was unfortunately not able to recreate the interesting part of your problem (your printf inside the thread target function seeming to have been called twice). Each method of compilation (-lpthread and -pthread) gives me the same result: I get the prints from inside main, but none of the printing from within the thread target (as you mentioned you saw on your first run). I think this is just a timing issue, with the thread target not "getting around to" printing before main exits. In fact, just sleeping for 1/100 second before returning from main gets me the thread target function's printing. Give it a try and let us know what you see:

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#include<string.h>
#include<pthread.h>
#include <unistd.h>

void * func(void * temp)
{
    printf("inside function\n");
    return NULL;
}

int main()
{
    pthread_t pt1;
    printf("creating thread\n");
    pthread_create(&pt1,NULL,&func,NULL);
    printf("inside main created thread\n");

    /* ZzzzzZZZ... */
    usleep(10000);

    return 0;
}

I played around with the delay time, and even with 1/1000000 second: usleep(1); I still get all of my expected printfs. As the sleep delay decreases, the printing is more likely to occur out of order, which I would expect to see.

So regarding the multiple prints: As many before me pointed out, printf and the like operate on global structures, and are not reentrant. I'd be interested to see your output if you flushed stdout after your printf, all being protected by a mutex:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void * func(void * temp)
{
    pthread_mutex_lock(&mutex);
    printf("inside function\n");
    fflush(stdout);
    pthread_mutex_unlock(&mutex);

    return NULL;
}

int main()
{
    pthread_t pt1;

    pthread_mutex_lock(&mutex);
    printf("creating thread\n");
    fflush(stdout);
    pthread_mutex_unlock(&mutex);

    pthread_create(&pt1,NULL,&func,NULL);

    pthread_mutex_lock(&mutex);
    printf("inside main created thread\n");
    fflush(stdout);
    pthread_mutex_unlock(&mutex);

    usleep(10000);

    return 0;
}

EDIT

I'm sorry, I wasn't 100% clear when I suggested using fflush() above. I believe that the problem is that you are being interrupted between the time that the characters are pushed to the screen and when the buffer is flushed. When the buffer is then actually truely flushed, you've effectively pushed your string twice.

Upvotes: 1

Mohit Jain
Mohit Jain

Reputation: 30489

I observed this issue on gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5), glib version 2.15 with O2 flag. Without any optimization flag, this issue is not observed.

Why the output is strange
The C language specification does not make reference to any particular compiler, operating system, or CPU. It makes reference to an abstract machine that is a generalization of actual systems. This abstract machine (atleast up to C99 specs) is single threaded. So standard libraries (including printf) are not required to be thread safe by default. If you are using standard library functions across the threads (using some library for example posix libpthread), you are responsible for adding synchronization (mutex, semaphore, condvar etc) before accessing non-entrant standard library functions. If you don't, there may be surprising results from time to time and you should use at your own risk.

Some analysis at the environment where I can reproduce this issue
Analyzing the assembly generated for both version of flag, I can not find any significant difference (Onething noticeable, printfs are converted to puts)

Looking at the source for puts

int
_IO_puts (str)
     const char *str;
{
  int result = EOF;
  _IO_size_t len = strlen (str);
  _IO_acquire_lock (_IO_stdout);

  if ((_IO_vtable_offset (_IO_stdout) != 0
       || _IO_fwide (_IO_stdout, -1) == -1)
      && _IO_sputn (_IO_stdout, str, len) == len
      && _IO_putc_unlocked ('\n', _IO_stdout) != EOF)
    result = MIN (INT_MAX, len + 1);

  _IO_release_lock (_IO_stdout);
  return result;
}

#ifdef weak_alias
weak_alias (_IO_puts, puts)
#endif

It seems the problem lies in _IO_putc_unlocked('\n', _IO_stdout). This may flush the stream and may get killed before updating the stream state.

Learnings for multithreaded coding
When the main thread returns, it terminates the entire process. This includes all other threads. So signal all children threads to exit (or use pthread_kill) and either make main thread exit with pthread_exit or use pthread_join.

Upvotes: 3

Giuseppe Guerrini
Giuseppe Guerrini

Reputation: 4438

In general you can't assume that printf and related memory structures are thread-safe. It depends on the way stdio library has been implemented. In particular, malfunctions may happen when threads and processes are terminating, since the runtime library usually flushes the output buffers before exiting. I have already seen such a sort of behavior, and the solution is usually a mutex or semaphore to protect the output operations (more precisely, to protect the accesses to FILE objects).

Upvotes: 1

Related Questions