-1

I'm training on C++ and threads. I found the following code from this page and compiled it on my Ubuntu 20.04 machine:

// C program to show thread functions

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

void* func(void* arg)
{
    // detach the current thread
    // from the calling thread
    pthread_detach(pthread_self());

    usleep(3*1000000);
    printf("Inside the thread\n");

    // exit the current thread
    pthread_exit(NULL);
}

void fun()
{
    pthread_t ptid;

    // Creating a new thread
    pthread_create(&ptid, NULL, &func, NULL);
    printf("This line may be printed"
        " before thread terminates\n");

    // The following line terminates
    // the thread manually
    // pthread_cancel(ptid);

    // Compare the two threads created
    if(pthread_equal(ptid, pthread_self()))
        printf("Threads are equal\n");
    else
        printf("Threads are not equal\n");

    // Waiting for the created thread to terminate
    pthread_join(ptid, NULL);

    printf("This line will be printed"
        " after thread ends\n");

    pthread_exit(NULL);
}

// Driver code
int main()
{
    fun();
    return 0;
}

I just added a usleep in the thread function but the behavior doesn't change. If I understand everything correctly the message "This line will be printed after thread ends" shall be always printed at the very end of the program, when thread ptid is ended.

But in reality, it often happens that this ending message is printed and then after 3 seconds (due to usleep call) it is printed the message "Inside the thread", seeming that thread ptid is still alive and running.

Without the usleep (as per original code) happened the same just without the 3s wait in the middle.

What's going wrong?

Marek R
  • 32,568
  • 6
  • 55
  • 140
martin.p
  • 331
  • 3
  • 16
  • 5
    Do you see anything in the thread function that will explain this, by any chance? Do you know what each one of these POSIX thread functions do? If no, it does it really make sense to copy/paste some code, off some web page, that uses advanced operating system functions that you are not familiar with, and try to make sense of any changes to the code? Doesn't it make more sense to learn, from a good textbook, the proper way, how do use execution threads in C++, with ***full explanation***? And if you're "training on C++ and threads", you should be learning modern C++'s `std::thread` instead, – Sam Varshavchik Aug 12 '22 at 16:23
  • 4
    As an aside, geeksforgeeks is often terribly, fatally wrong, and a poor choice for learning. Any resource that claims to be showing you code written in "C/C++" should be a red flag. C++ has threading support built into the standard library itself, and this article is pretending it doesn't exist. – Drew Dormann Aug 12 '22 at 16:23
  • 2
    Oh geez. That is not good code, or a good explanation of pthreads. I really advise that you try to learn programming from a good textbook, rather than from random strangers on the internet. – Sneftel Aug 12 '22 at 16:25
  • Multithreaded programming is one of the most difficult topics to learn. It takes experience, and a *lot* of good, peer-reviewed reading material to get right -- you have books hundreds of pages, if not a thousand pages or more, concerning MT programming . Using geeksforgeeks as a resource is a very poor choice, given how they botch getting simple things right concerning C++. – PaulMcKenzie Aug 12 '22 at 16:26
  • 1
    And in conclusion to all of the above, the only productive way to learn C++ is with a good textbook. Any clown can upload a video to Youtube (even I can do it), or publish some nonsense on some web site (I can do that too, and I do). But only an edited, organized textbook will teach you C++, one step at a time, and explain C++ fundamentals. You will not effectively learn C++ from Youtube, some web site, or by doing useless coding puzzles. – Sam Varshavchik Aug 12 '22 at 16:28
  • I thought of sharing: – murugesan openssl Aug 12 '22 at 16:39
  • 2
    What was the reason you put a `pthread_detach()` call in your function? What effect did you want to create with that? https://man7.org/linux/man-pages/man3/pthread_detach.3.html – Galik Aug 12 '22 at 16:41
  • @Galik -- That's the knock-on effect of using bad websites to learn from. – PaulMcKenzie Aug 12 '22 at 16:48
  • @SamVarshavchik of course you are right, I also know that learning from one or more texts such a complex topic is the best thing. But as a hobbyist, with little time available, I tried to understand the explanation thoroughly before running it. After all, the only damage I've done is waste your time. The fact remains that I still don't understand why it doesn't work. Outdated library? – martin.p Aug 12 '22 at 16:51
  • @martin.p *But as a hobbyist, with little time available, I tried to understand the explanation thoroughly before running it* -- Then you're out of luck when it comes to multi-threaded programming. It takes experience to understand all of the details -- this isn't something where you take out a pamphlet of commands, look them up, and understand what is going on. – PaulMcKenzie Aug 12 '22 at 16:52
  • 3
    Why do you call `pthread_join` on a potentially `detached` thread (potentially because you don't know that the thread has even ran yet.. It likely hasn't, and you're sitting there waiting on it to finish running (>= 3s)). Also, `pthread_exit` isn't what you want inside of `fun`.. The function MUST RETURN something, and `pthread_exit` does not return to the caller. As you can see, removing both `join` and `exit` from `fun` function, will do what you want. – Brandon Aug 12 '22 at 16:53
  • Simple and multithreading are nearly mutually exclusive. – user4581301 Aug 12 '22 at 16:54
  • 1
    @martin.p Note that all of the comments are on the code you copied and pasted directly from that site. Do you see all of the issues with code you thought was ok, but turns out to be wrong in many ways? Just the fact that a function that is supposed to return a `void *` doesn't return anything should give you pause as to who gets to post articles on that site. There seems to be absolutely no peer-review there, and instead, you get page with "Likes" from unsuspecting new programmers. – PaulMcKenzie Aug 12 '22 at 16:57
  • @Galik as I said, after trying to thoroughly understand the logic of the various functions and the code I simply copied and pasted it to test it. But in fact something is not working and I do not understand why (besides the fact that it is not the best site in the world to copy from ....). The purpose of pthread_detach() function should be to release the completion of the thread from the conclusion of the main program, even if this has to wait for its conclusion. – martin.p Aug 12 '22 at 16:58
  • @PaulMcKenzie I understood I'm a place where I shouldn't be, thanks for the advice. Others tried to give an explanation and thanks for that. Sooner or later I will understand, be sure. – martin.p Aug 12 '22 at 17:05
  • C or C++? Pick one. – n. m. could be an AI Aug 12 '22 at 17:39
  • 1
    @PaulMcKenzie `pthread_exit` does not return. – n. m. could be an AI Aug 12 '22 at 17:40
  • @n.1.8e9-where's-my-sharem. -- Still, the code should have a `void` return and not `void *`. That is basically what my point was -- a lack of a peer-review of the code that gets posted on that site. – PaulMcKenzie Aug 12 '22 at 17:44
  • 1
    @PaulMcKenzie Nope, a thread function must have a specific type, `void*(void*)`. – n. m. could be an AI Aug 12 '22 at 17:47
  • If you're really looking to "trying to thoroughly understand the logic of the various functions and the code" then the only place to look for that would be a good C++ textbook on multithreading. That's what textbooks are for. Stackoverflow is not a replacement for a textbook. – Sam Varshavchik Aug 12 '22 at 17:51
  • @SamVarshavchik ok. In the meantime I got an answer. Then I will search for a book. Any suggestion? – martin.p Aug 12 '22 at 18:29
  • 1
    Echoing what Sam Varshavchik said: Any resource that advises you to use the pthreads library in a C++ program is out-of-date. Don't use it. Look for a tutorial that teaches you about `std::thread` instead. The pthreads library is not part of the language standard, and you should not expect it to be supported in the future. – Solomon Slow Aug 12 '22 at 20:50
  • Stackoverflow maintains [a list of recommended C++ textbooks](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Sam Varshavchik Aug 12 '22 at 22:55
  • @SamVarshavchik thank you and thanks to Solomon Slow too. Honestly speaking I felt mortified by some comments. I'm a beginner and hobbyist. My target is to learn as much as I can to develope some project, not becoming a "guru" of coding. I will read books if I have the opportunity but learn from experts is an other big opportunity. So guys take it easy with me ;-) – martin.p Aug 12 '22 at 23:15
  • Well, all the "experts" here are saying the same thing -- a textbook. That's how the "experts" have learned C++. That's why they're experts [instead of Google programmers](https://pvs-studio.com/en/blog/posts/0952/). – Sam Varshavchik Aug 13 '22 at 00:08
  • The "all or nothing" approach does not always satisfy the need. As I said I am far from being a professional and wanting to become one and for my purposes it might be enough to be a "google programmer". However, as I said, I will find a good text to read because it is my intention to deepen, in parallel to the rest. I hope I have made my point clear. – martin.p Aug 13 '22 at 07:55

1 Answers1

2

A spotted in the comments, the source of the main issue of your code is that you call pthread_detach.

The later pthread_join will just ignore the thread you detach.

At this point all thread "live their own life" which means the the only remaining synchronization mechanism is at the "exit" (when main returns). On exit, the compiler added some code that will wait for all threads to terminate.

So as threads are not synchronized in any way, what is happening is just a race condition.

When adding the usleep, you just delay the fist thread enough for the other one to have much time to finish first.

When no usleep, the race just produces random order of logs.

Worth to notice that stdout is bufferized, so the output may not be displayed at the time the printf call is done.

Remove the pthread_detach() will restore the synchro provided by pthread_join, so the log will appea in the order you expect (if I put aside the stdout bufferization pb)

OznOg
  • 4,440
  • 2
  • 26
  • 35
  • Very clear explanation, thanks. I will try it asap. Do you suggest try different (i.e more recent) libraries? – martin.p Aug 12 '22 at 18:26
  • well modern c++ (post c++ 11) comes with native threads, so using pthread directly is quite deprecated. Moreover, modern pattern also deprecate direct use of threads, but rather use async stuff like std::async. – OznOg Aug 12 '22 at 19:04
  • Again, thanks for your time and very constructive help. I will try to deepen the topic you suggested to me. – martin.p Aug 12 '22 at 20:44
  • 1
    From what I've read, the compiler does not add code to wait for all threads to terminate on exit; rather, any still-running threads are killed (and likely invoke undefined behavior in the meantime since they are running concurrently with the destruction of static variables and other process-wide resources by the main() thread): https://stackoverflow.com/questions/19744250/what-happens-to-a-detached-thread-when-main-exits – Jeremy Friesner Aug 12 '22 at 21:02
  • This seem to be different with pthread used directly because if the thread was killed, you would never see its message. Using std::thread has a different behaviour here, I'll have a look at what is different behind the scene – OznOg Aug 13 '22 at 08:38