Thread: std::thread leads to Abort

  1. #31
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    There are some discussions here about the "-pthread" switch -
    Bug 42198 – [C++0x] Using std::thread without -pthread causes immediate crash

    Apparently it's due to -pthread being platform-specific. That's why it's not implied.

  2. #32
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Elysia View Post
    I'm only going to say say thing now...
    What you are doing is wrong, absolutely wrong.
    A lock is meant to cause exclusive access to certain resources. This is clearly not what you are trying to do.
    What you need is an event. The thread should notify the main function that it has completed, or the main thread can wait until the thread is complete.
    What you are doing ends up in a race condition. That is, the code may have two outcomes depending on which thread acquires the lock first.
    An event would be useful if you wanted one thread to generate the primes and then nofity another thread when it was done.
    If, as I suggested, someone wanted one thread producing primes and other threads consuming them (which is what I took the original post to mean) then a lock is precisely what you want.
    What the OP has here is something where threading is completely pointless. If you create a thread and then immediately join then it is the same as a direct function call.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  3. #33
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, it is. I was merely explaining the difference between a lock and an event and in which situation you should use which. In this case, the thread is really pointless as you say.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #34
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Useless, until I start using primes in a mt application. For example, I'm going to factor integers with 16 threads. The lock is there to keep more than one thread from entering extend_primes() at the same time. The possibility of more than one needing to extend the list at the same time is rather small. I'm going to go even further and make a unique lock that wakes to check if the primes it's waiting to generate have been generated by the current prime-generating thread (which would happen if I started with primes = 2, 3 had two threads, one generating to 103, which is holding the lock, and another only needing 19, which calls while other is holding the lock; once the first thread has generated primes up to 19, the second will return and continue on its execution).

    What I was doing in main() was a simple concept check to get the threading working; it appears y'all assume too quickly that I must be a total fool.

  5. #35
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Not asuming you are a fool at all. It just helps a lot to have information that you've now only just provided, a little earlier. I knew there had to be some point to all this, but we could not even determine what you were trying to do, so we didn't know how to advise you.
    How do you plan on splitting up the work over multiple threads?
    Why don't you start with a decent sized hard-coded list of initial primes?
    What size numbers are we talking about here?
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #36
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Quote Originally Posted by iMalc View Post
    Not asuming you are a fool at all. It just helps a lot to have information that you've now only just provided, a little earlier. I knew there had to be some point to all this, but we could not even determine what you were trying to do, so we didn't know how to advise you.
    No, there was no initial point. I just saw the need to leave the multithreading option open.

    Quote Originally Posted by iMalc View Post
    How do you plan on splitting up the work over multiple threads?
    It will have a per number granularity. I will create a thread for each number, and the thread will compute the factors optimally given the list of primes. There will be a number of threads computing the factors of different numbers. Upon completion of computation, a thread will lock the list of numbers and their factors, add its number and its list, then terminate. The algorithm I'm using to do this, specifically, to save the results and to manage the threads, reeks of kludge, so keep an eye out for a new thread by me.

    Quote Originally Posted by iMalc View Post
    Why don't you start with a decent sized hard-coded list of initial primes?
    What size numbers are we talking about here?
    Good idea, for later. We're talking about numbers from 2 to n, where n is a number I haven't decided on yet. :P

  7. #37
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Elysia View Post
    It boggles your mind, but according to...
    c++ - thread destructors in C++0x vs boost - Stack Overflow
    ...it is the correct behavior.

    In other words, we're stuck with a useless thread object -_-
    It's not useless. The truth is that there is *no* fully reasonable behavior for destructing a thread object whose thread is still running, and just aborting the application is actually the least of all evils.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #38
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by User Name: View Post
    No, there was no initial point. I just saw the need to leave the multithreading option open.

    It will have a per number granularity. I will create a thread for each number, and the thread will compute the factors optimally given the list of primes. There will be a number of threads computing the factors of different numbers. Upon completion of computation, a thread will lock the list of numbers and their factors, add its number and its list, then terminate. The algorithm I'm using to do this, specifically, to save the results and to manage the threads, reeks of kludge, so keep an eye out for a new thread by me.
    You might find that if you do that, that the overhead of setting up and tearing down a thread for each prime makes is barely faster than just running single threaded, because most numbers are determined to be composite very quickly.
    Also, if once a number is prime, you add it to the list, you'll need to handle the possibility that it wont be at the very end of the list because the threads will essentially constantly be completing their jobs in random order.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #39
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    It's not useless. The truth is that there is *no* fully reasonable behavior for destructing a thread object whose thread is still running, and just aborting the application is actually the least of all evils.
    The problem is that now we are forced to rely on some out-of-scope code instead of the destructor when it comes to threads, and that's why I said useless. We can't rely on RAII with threads.
    I fully understand the problem (I read the article), but I don't really fully agree with their solution.
    One solution might, for example, be to signal the thread that it should exit. One might also think that it is possible to choose whether to signal the thread to exit or not once the thread goes out of scope.
    But IMHO, since RAII is all about objects encapsulating a resource (ie, acquire the resource in the constructor, release in the destructor), it feels like threads shouldn't be an exception. In the constructor, the thread is created and in the destructor, the thread is destroyed.
    That would have allowed us to retain RAII semantics. I don't know how feasible it is since I haven't tested it, obviously.

    Anyway, useless is my humble opinion.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #40
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Elysia View Post
    One solution might, for example, be to signal the thread that it should exit.
    Except that there is no standard way to do that. Thread cancellation was removed.

    One might also think that it is possible to choose whether to signal the thread to exit or not once the thread goes out of scope.
    Well, you can always detach. Of course, detaching comes with its own problems.

    But IMHO, since RAII is all about objects encapsulating a resource (ie, acquire the resource in the constructor, release in the destructor), it feels like threads shouldn't be an exception.
    Your feeling is wrong. Threads ARE an exception, since they're the only resource that is implicitly referenced by running code (namely, the code running in the thread). When a thread object belonging to a running thread goes out of scope, this implicit reference is dangling, which is dangerous. You can't just kill the thread. You can't signal it, since there is no mechanism for doing so, and anyway there is no telling how long it would take for the thread to react. You can't leave it running, since it violates the expectation that the thread only lives as long as the scope of the thread object. You can't do anything that doesn't lead to subtle bugs, so the decision to do the un-subtle thing is the right one IMO.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #41
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    He isn't wrong. Threads are the conceptual resources as any other resource object because, as you implied, a thread shouldn't really be allowed to live beyond the object that owns it. If the thread, or the process owning the thread, is to be killed or joined treating the object as conceptually special is silly.

    With the mechanism that was chosen, programmers are forced to choose between layering bad exception propagation handling over all code that uses a `std::thread' resource, defaulting to ancient behavior of "just crash it is the best we can do", carefully wrapping the `std::thread' object with higher level code as a means of developing a mechanism for suspending the thread of execution, or developing another object solely to manage the `std::thread' object. All of those options suck! I don't like for my code to "just crash" but that is unfortunately the only option that is easy to get right. (I've already seen a tidy bit of code that fails to do the second option correctly.)

    It is true that a `std::thread' object is implicitly referenced by the thread, but so what? As you implied, every possible mechanism is at best a compromise. You agree with the alternative chosen as a "best fit"; a lot of people don't. I certainly don't, but then I don't like "joining" option either. (I like the idea of using constructs that can force termination of the thread, but that is really only yet another compromise and a difficult one to implement correctly.)

    The mechanism chosen to prevent a dangling reference invades every aspect of code using a `std::thread' object. I can't simply contain an object and assume the default destructor will do the right thing unless the definition of "right thing" is "crash without context". I can't simply execute my code under the assumption the the error context, the exception objects, I've carefully constructed will be honored because they will not be honored unless I manually wrap the code with a "try" block and "rethrow" the the exception. (Which, personally, I find extremely distasteful in any context and absolutely wrong in most.) I can't just write even the simplest template functions unless I place burdens on the types used with it because I can't know what sorts of exceptions the types might throw and in what context. All of this makes writing and debugging any code using `std::thread' far from easy and I feel that ultimately many will come to the same conclusion and will continue to use other mechanisms for thread management even if it behaves exactly as they may have imagined it should.

    Honestly, I don't even disagree with the decision. No, really, I don't, but you can't fault someone for not understanding it.

    Soma

  12. #42
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by phantomotap View Post
    He isn't wrong.
    Threads are special. Do you disagree with that?

    Threads are the conceptual resources as any other resource object because, as you implied, a thread shouldn't really be allowed to live beyond the object that owns it.
    But unlike any other resource, you cannot simply dispose of a thread just like that. (At least any other resource I can think of.)

    The mechanism chosen to prevent a dangling reference invades every aspect of code using a `std::thread' object.
    True. As would any other.

    I can't simply contain an object and assume the default destructor will do the right thing unless the definition of "right thing" is "crash without context".
    How do you feel about "hang indefinitely" (cancellation) and "corrupt program state" (termination)?
    "Crash without context" is not necessarily true either. GCC is, in my opinion, being stupid here. The least it could do is print a message to stderr saying "destructing unjoined thread object".

    I can't just write even the simplest template functions unless I place burdens on the types used with it because I can't know what sorts of exceptions the types might throw and in what context.
    I'm not sure what you mean by that. Almost any template function places burdens regarding exceptions on the types you give it.

    All of this makes writing and debugging any code using `std::thread' far from easy and I feel that ultimately many will come to the same conclusion and will continue to use other mechanisms for thread management even if it behaves exactly as they may have imagined it should.
    I think the problem has been blown way out of proportion. Yes, the OP stumbled across the problem. Yes, he was confused because it's not exactly intuitive. But he noticed the problem and he learned about the special behavior - something he would not have done as readily if the behavior of a destructed thread was something else.

    In practice, though, I don't think the problem will occur all that often. Threads are low-level primitives anyway. I expect them to be nicely wrapped up (e.g. in std::async) a lot.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #43
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    Your feeling is wrong. Threads ARE an exception, since they're the only resource that is implicitly referenced by running code (namely, the code running in the thread). When a thread object belonging to a running thread goes out of scope, this implicit reference is dangling, which is dangerous. You can't just kill the thread. You can't signal it, since there is no mechanism for doing so, and anyway there is no telling how long it would take for the thread to react. You can't leave it running, since it violates the expectation that the thread only lives as long as the scope of the thread object. You can't do anything that doesn't lead to subtle bugs, so the decision to do the un-subtle thing is the right one IMO.
    This is not right.
    Because the standard chose to do this, we're stuck with it forever and ever. It's not a mistake they can go back and fix.
    The better option, if you ask me, would have been to revoke std::thread from the standard entirely until a safe way to fix this could be proposed. We already have boost, and while not perfect, works. It's not like the standard std::thread would work any better, so would there be any good practical reason to standardize it with such defects?

    I cannot now write any good exception-safe code using threads without some sort of special handling code for std::thread in both the thread creating it (making sure to make it so that the thread will be detached in some way before the constructor runs; either by it terminating on its own, detaching or killing it), and in the actual thread whose code we run (to make sure it terminates gracefully).
    Pretty? I think not. And now we're stuck with this.

    It would be have been far more ideal for the standard to propose a solution to this problem before standardizing std::thread (such as some signal system).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #44
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Threads are special. Do you disagree with that?
    No. That's exactly the opposite of what I was saying.

    You have only chosen to make them special conceptually. A lot of real resources (such as a printer) can be put into a state where the conceptual resource exists beyond the handle (a controlling object) that manages that resource. (I'm not talking about the printer, for example, but the print job associated with our fictional object.)

    There are many kinds of resources and I am considering them all. I'm not just comparing purely virtual objects of a probably plentiful nature like RAM or files. I'm comparing both abstract and entirely real resources that may need to be managed. At the very least, they would all be special in the same way.

    But unlike any other resource, you cannot simply dispose of a thread just like that.
    Considering the printer example again, you can't simply dispose of a print job either. (Actually, you can simply dispose of a print job depending on the platform, but depending on the platform you can also simply dispose of a thread.) With that in mind, it is often necessary to mark the job as terminated, process the job until it can be safely halted, terminate the job, and then free the resource.

    In the case of a printer, simply killing the job can jam the physical printer; simply terminating the application would not be a realistic option for many applications. If you tried to wrap this printer resource in "RAII", you'd have to consider and compromise.

    True. As would any other.
    That is not necessarily true. One of the many other options, "joining" by default for example, may hang in the face of an exception, but the exception context would be processed without the tricks which would be necessary with the chosen mechanism. This approach, too, requires compromise.

    How do you feel about "hang indefinitely" (cancellation) and "corrupt program state" (termination)?
    The chosen mechanism is process termination so I have no idea why you put that in parentheses in this context. You'll have to explain a little more if you want me to respond to that.

    I like the idea of putting mechanisms in place to suspend and then terminate the thread. This would require more primitives and the code path to be threaded would have to be carefully constructed against those primitives. (If it was not so written it might hang indefinitely, but it wouldn't be the standard at fault.) It represents one of many options, but like everything else requires compromise.

    Naturally, I don't like the idea of "hang indefinitely", but that need not necessarily be the case; certainly such a mechanism as "terminate the thread" might, but it might only represent a response similar to what already happens by some compilers when an exception is thrown leaving the job, but not necessarily anything else, in a valid but unknown state.

    "Crash without context" is not necessarily true either. GCC is, in my opinion, being stupid here. The least it could do is print a message to stderr saying "destructing unjoined thread object".
    I know what you are saying. If the compiler provided more context, it would be less of an issue. I'm not sure though that "GCC" is just being stupid. The standard requires that `std::terminate' be called, that static objects for standard objects exist "at least until `main' exits", and also that `std::uncaught_exception()' exists. You'd think that would be enough to ensure that exception context in the case of the issue at hand arising could be processed correctly. It isn't enough for some compilers because of the way exceptions are processed internally. I'm not sure "provide developers with a better standard implementation" is enough for some vendors to change things as much as would be necessary.

    *shrug*

    Strangely, "GCC" is not such a compiler. You can change the implementation to provide more context without going outside standard C++ with their implementation.

    I can't write the code here at this moment, but it is basically using `std::uncaught_exception()' in the context of a terminate handler to "rethrow" and then conditionally reprocess the exception with a series of "catch blocks".

    Actually, I'm not sure that still works with "GCC". It would have once worked. If you don't see what I'm talking about but want to try it out let me know.

    I'm not sure what you mean by that. Almost any template function places burdens regarding exceptions on the types you give it.
    I'm sorry for the confusion. It is absolutely true that many templates place burdens on the types processed. In many cases it is necessary to assume that certain operations will not raise an exception of any kind. It is also true that many operations are assumed to be exception safe even in the face of an exception being raised. Unfortunately, in the case of the chosen mechanism, being exception safe isn't sufficient if I want the template to process that context.

    Granted, if the standard required that the context of an exception be processed when this situation occurred this would not be an issue and would not compromise my application. Perhaps we will see that in a further correction to the standard.

    I think the problem has been blown way out of proportion.
    I agree completely. It doesn't behave in a way that is naturally expected. The chosen mechanism has a lot of issues that must be faced, but so would any other option. It is largely an issue of education.

    However, because it doesn't do what so many people expect requiring unfamiliar or unacceptable constructs, I believe that it will be largely ignored.

    *shrug*

    I don't mean to repeat myself there. You don't see it as an issue, or rather, expect that it will not be an issue once people understand it and how to deal with it. I fully understand; it just happens that I strongly disagree with it.

    Soma

  15. #45
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Quote Originally Posted by iMalc View Post
    You might find that if you do that, that the overhead of setting up and tearing down a thread for each prime makes is barely faster than just running single threaded, because most numbers are determined to be composite very quickly.
    Also, if once a number is prime, you add it to the list, you'll need to handle the possibility that it wont be at the very end of the list because the threads will essentially constantly be completing their jobs in random order.
    A thread to check each number for prime-ness would be excessive, but that's not what I'm doing. I'm creating a thread to factor each number. I see that one could easily make the argument that prime checking ~ factoring, but the point of it being multithreaded, to the point of having more than 2 threads, is to generate the list of numbers and their factors faster. If all I was doing was creating one thread to factor a number and leaving the original thread to manage it's child, then I would agree, it would be pointless. But, what I'm doing is creating 16 threads constantly factoring numbers with 1 thread managing their creating and joining.

    It is factoring that is per thread. Primes are generated in a mutually exclusive function (called by a factoring thread when the list of primes isn't long enough), so as to insure they are inserted in order. The lists of factors are added asynchronously by each thread to a std::map, which maintains order automatically.

    EDIT: I started another thread for my logic problems, but it didn't get any replies. Here it is: Infinite loop when not debugging? (multithreaded)
    Last edited by User Name:; 06-07-2011 at 01:25 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Weird typo leads to interesting result... what does it mean?
    By pollypocket4eva in forum C++ Programming
    Replies: 4
    Last Post: 06-17-2010, 03:30 AM
  2. abort() causes a segfault
    By JFonseka in forum C Programming
    Replies: 12
    Last Post: 04-16-2008, 01:40 AM
  3. abort()
    By swgh in forum C++ Programming
    Replies: 5
    Last Post: 02-22-2008, 04:11 AM
  4. Abort Procedure
    By incognito in forum Windows Programming
    Replies: 5
    Last Post: 01-02-2004, 09:49 PM
  5. Western society leads to unsatisfaction
    By Zewu in forum A Brief History of Cprogramming.com
    Replies: 20
    Last Post: 08-06-2003, 03:45 PM