#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
printf("hello, world \n");
return 0;
}
int main(void)
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread_func, NULL);
pthread_create(&t2, NULL, thread_func, NULL);
printf("t1 = %d\n",t1);
printf("t2 = %d\n",t2);
return 0;
}
The above program creates two threads, where each thread prints "Hello World".
So, as per my understanding, the "Hello world" should print a maximum 2 times.
However, while executing the same program multiple times(back to back), there are scenarios where "Hello world" is being printed more than 2 times. So I am unclear how it is getting printed an unexpected number of times?
Here are the sample outputs:
[rr@ar ~]$ ./a.out
t1 = 1290651392
t2 = 1282258688
hello, world
hello, world
[rr@ar ~]$ ./a.out
t1 = 1530119936
t2 = 1521727232
hello, world
hello, world
hello, world
As shown above, after executing the program for many times, "hello, world" is printed 3 times. Can anyone please advise how come it got printed 3 times?
If thread is not NULL, pthread_create() stores the ID of the created thread in the location referenced by thread. At creation, the thread executes start, with arg as its sole argument. The calling function must ensure that arg remains valid for the new thread throughout its lifetime.
The pthread_create() function will fail if: [EAGAIN] The system lacked the necessary resources to create another thread, or the system-imposed limit on the total number of threads in a process PTHREAD_THREADS_MAX would be exceeded.
pthread_create: used to create a new thread. Syntax: int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); Parameters: thread: pointer to an unsigned integer value that returns the thread id of the thread created.
If pthread_create() completes successfully, thread will contain the ID of the created thread. If it fails, no new thread is created, and the contents of the location referenced by thread are undefined.
You experienced a thread-safety problem. I ran your code several times in Linux 16.04 and it produces many different outputs, while the one with 3 hello world
message being rare it exists. More frequently there is no output at all which means that main
terminates faster than threads being able to finish their outputs. Sometime partial outputs are produced like:
t1=xxxx
t2=yyyy
he
That means that the main
is exiting while only one thread was able to push some characters in the stdout buffer. Remember that a normal return from main
is equivalent to a call to exit
which flushes stdio buffers.
While I am unable to really understand what happens behind the scene when you observe 3 messages, I suspect that there exists a run race that let the main
flushing a buffer that is currently being flush by one of the threads. Without examining very carefully the source code of printf
it is very hard to say more. A possible (rough) scenario would looks like:
hello world
hello world
hello world
printf
is not defined as thread-safe, which means that implementors may realize it as such or not (probably not in most cases). So you need, as with any function that uses some shared resource, some mutex to prevents buffer concurrency and such.
In your case, this should be roughly solved (3 outputs) by joining the threads in the main which will prevent main
exiting/flushing before threads termination. But be aware that this will not solve other concurrency problems (two threads accessing the same buffer...).
Well, let me show an scenario where this can happen. You probably know (if you don't, please read the appropiate manual page) that printf()
is one of the functions that is not thread safe of the standard library (there is a list in the pthread_<something>
, somewhere) and you probably also know that printf(3)
stores its data in a buffer previously to issue the write(2)
system call to actually write the data to stdout.
printf()
call that puts a compllete "Hello, world\n"
message in the buffer, and prepares to write(2)
it, as a consequence of the terminal being a tty device and a \n
ends the output string.printf(2)
data (and fills the same buffer with a second copy of "Hello, world\n"
) and for the same reason, prepares and completely executes a write(2)
syscall of the whole buffer (which now contains two messages) flushes the buffer. this makes "Hello, world\n"
to appear twice.write(2)
system call (both threads cannot make simultaneous write(2)
calls to the same inode ---this is warranted by the system kernel) flushes it's view (which probably is stored in its stack, and includes only the reference to the first message) of the buffer (which finished at the end of the first "Hello, world\n"
) and makes another write of one more "Hellow, world\n"
message)Final score: Three "Hellow, world\n"
messages at the terminal.
The most probable thing is that getting three messages is difficult to happen, as you need one of the threads to bypass the other in the time printf
decides it is time to flush the buffer, after filling it (which is a short time) and then get first into the blocking write(2)
call (as explained before, both threads cannot be involved in a write(2)
call at the same time to the same file, that's not permitted by the kernel)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With