6

this is my first pthread program, and I have no idea why the printf statement get printed twice in child thread:

int x = 1;

void *func(void *p)
{
    x = x + 1;
    printf("tid %ld: x is %d\n", pthread_self(), x);
    return NULL;
}

int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    printf("main thread: %ld\n", pthread_self());

    func(NULL);
}

Observed output on my platform (Linux 3.2.0-32-generic #51-Ubuntu SMP x86_64 GNU/Linux):

1.
main thread: 140144423188224
tid 140144423188224: x is 2

2.
main thread: 140144423188224
tid 140144423188224: x is 3

3.
main thread: 139716926285568
tid 139716926285568: x is 2
tid 139716918028032: x is 3
tid 139716918028032: x is 3

4.
main thread: 139923881056000
tid 139923881056000: x is 3
tid 139923872798464tid 139923872798464: x is 2

for 3, two output lines from the child thread

for 4, the same as 3, and even the outputs are interleaved.

chuchao333
  • 1,438
  • 1
  • 14
  • 22
  • On multithread application you need to worry about the resource that used by more than on thread, on your example the screen output is the resource which used by multithreads , so need to use mutex to handle this. – Amir Naghizadeh Nov 25 '12 at 12:17
  • @tAmirNaghizadeh: on POSIX (and Linux) functions that use a `FILE*` are specified to take a lock on the object (except for the few I/O functions that specifically don't take a lock and have "unlocked" as part of their name). – Michael Burr Nov 25 '12 at 20:20
  • 1
    I know I've seen another question on SO in the last month or so about the extra line of output when a thread isn't joined and the process ends, but I can't find it now (maybe it's been deleted?). An older one that was never satisfactorily answered: http://stackoverflow.com/questions/10322175 I hope a decent answer can be given on this. – Michael Burr Nov 25 '12 at 20:23
  • @MichaelBurr: So,what's make the example 4 looks liked that? – Amir Naghizadeh Nov 26 '12 at 06:26
  • 1
    @tAmirNaghizadeh: I think it's the same problem that causes the thread's output to be duplicated sometimes when the process ends without joining the thread. I think it's a problem in glibc, but I'm willing for someone to point out why it's OK for the system to do that (ie., point out where the undefined behavior is). My argument that `printf()` should be atomic with respect to other `printf()` calls (actually, any POSIX function that uses `stdout`) in a process is in this answer and comments: http://stackoverflow.com/a/13190750/12711 – Michael Burr Nov 26 '12 at 06:35
  • @MichaelBurr, so you are sure the output get duplicated rather than the thread get executed twice (as someone explained below)? I also tend to believe this since it's so tricky if that's the case. The two executions of the child thread both print out "x = 3" – chuchao333 Nov 26 '12 at 06:53
  • @chuchao333: the thread doesn't get executed twice (however, it may start execution, get switched away from, then resume execution any number of times). The value of `x` isn't well-defined for much of the program because it's being modified without proper synchronization. So I wouldn't try to make too much sense out of what the value of `x` is that's printed. However, I think you'll find that you still get duplicated output from the thread if you remove all use of `x` (ie., the undefined behavior of modifying `x` isn't the cause of the duplicated output). – Michael Burr Nov 26 '12 at 07:20
  • 1
    An update on this: this problem has an open bug report against glibc: https://sourceware.org/bugzilla/show_bug.cgi?id=14697 – Michael Burr May 22 '15 at 22:03

3 Answers3

2

Threading generally occurs by time-division multiplexing. It is generally in-efficient for the processor to switch evenly between two threads, as this requires more effort and higher context switching. Typically what you'll find is a thread will execute several times before switching (as is the case with examples 3 and 4. The child thread executes more than once before it is finally terminated (because the main thread exited).

Example 2: I don't know why x is increased by the child thread while there is no output.

Consider this. Main thread executes. it calls the pthread and a new thread is created.The new child thread increments x. Before the child thread is able to complete the printf statement the main thread kicks in. All of a sudden it also increments x. The main thread is however also able to run the printf statement. Suddenly x is now equal to 3. The main thread now terminates (also causing the child 3 to exit). This is likely what happened in your case for example 2.

Examples 3 clearly shows that the variable x has been corrupted due to inefficient locking and stack data corruption!!

For more info on what a thread is.

Link 1 - Additional info about threading

Link 2 - Additional info about threading

Also what you'll find is that because you are using the global variable of x, access to this variable is shared amongst the threads. This is bad.. VERY VERY bad as threads accessing the same variable create race conditions and data corruption due to multiple read writes occurring on the same register for the variable x. It is for this reason that mutexes are used which essentially create a lock whilst variables are being updated to prevent multiple threads attempting to modify the same variable at the same time. Mutex locks will ensure that x is updated sequentially and not sporadically as in your case.

See this link for more about Pthreads in General and Mutex locking examples.
Pthreads and Mutex variables

Cheers,
Peter

Community
  • 1
  • 1
Peter H
  • 871
  • 1
  • 10
  • 33
  • @Peter H "a thread will execute several times before switching (as is the case with examples 3 and 4.)", then this is so tricky in my case, the child thread is executed twice and both get switched just after main thread updated x and before itself updating x? – chuchao333 Nov 25 '12 at 12:49
  • The lifetime of every thread executing is limited to that of the main thread unless joined. If you want to ensure that the child threads execute completely this is where you need to use the function pthread_join, by which it will join the child thread to the main thread. See [This link for examples](http://www.thegeekstuff.com/2012/04/terminate-c-thread/#more-10260) – Peter H Nov 29 '12 at 07:02
  • @PeterH in the Link 2, it clearly states that a thread is terminated when it "returns normally from its starting routine. Its work is done." This clashes with the first part of your response, that a thread executes several times before switching. (The implication being that the thread is simply _running_ multiple times and therefore calling `printf` multiple times) The likely issue with the repeated outputs is the bug referenced by @ZanLynx – Mike Lui Aug 17 '16 at 16:40
  • @MitchLaskis A thread can terminate when it has finished its work, this is correct...BUT a child thread can be terminated early and abruptly upon the completion of the main thread (I.E The child thread may never complete if main completes first). Since the author is calling func both as a child thread and the main thread its difficult to tell. It is entirely possible that the extra printf in scenario 3 is caused by a bug in the stdio buffers described by Zan, but the lack of locking on variable x makes it very difficult to tell. End Story...Implement locking/mutexes to ensure thread safety. – Peter H Aug 18 '16 at 23:52
2

Hmm. your example uses the same "resources" from different threads. One resource is the variable x, the other one is the stdout-file. So you should use mutexes as shown down here. Also a pthread_join at the end waits for the other thread to finish its job. (Usually a good idea would also be to check the return-codes of all these pthread... calls)

#include <pthread.h>
#include <stdio.h>
int x = 1;
pthread_mutex_t mutex;

void *func(void *p)
{
    pthread_mutex_lock (&mutex);
    x = x + 1;
    printf("tid %ld: x is %d\n", pthread_self(), x);
    pthread_mutex_unlock (&mutex);
    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, 0);

    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    pthread_mutex_lock (&mutex);
    printf("main thread:  %ld\n", pthread_self());
    pthread_mutex_unlock (&mutex);

    func(NULL);
    pthread_join (tid, 0);
}
pbhd
  • 4,384
  • 1
  • 20
  • 26
  • Ok, this answer is partially wrong, there are several questions here dealing with that, e.g. http://stackoverflow.com/questions/467938/stdout-thread-safe-in-c-on-linux. Played with the code, and removed the mutex everywhere except where x is incremented. Still works always correct. But when pthread_join is removed, things start getting weird. My explanation for that behavior is, that without the join, the main exits and the image rundown starts, which might involve deleting structures (mutexes?) in glibc, which then makes printf no longer behave correctly. – pbhd Nov 25 '12 at 21:44
2

It looks like the real answer is Michael Burr's comment which references this glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14697

In summary, glibc does not handle the stdio buffers correctly during program exit.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131