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.
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.
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"
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.
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"
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.
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
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
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"
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.
Except that there is no standard way to do that. Thread cancellation was removed.
Well, you can always detach. Of course, detaching comes with its own problems.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.
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.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.
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
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
Threads are special. Do you disagree with that?
But unlike any other resource, you cannot simply dispose of a thread just like that. (At least any other resource I can think of.)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.
True. As would any other.The mechanism chosen to prevent a dangling reference invades every aspect of code using a `std::thread' object.
How do you feel about "hang indefinitely" (cancellation) and "corrupt program state" (termination)?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".
"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'm not sure what you mean by that. Almost any template function places burdens regarding exceptions on the types you give it.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 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.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.
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
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).
No. That's exactly the opposite of what I was saying.Threads are special. Do you disagree with that?
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.
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.But unlike any other resource, you cannot simply dispose of a thread just like that.
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.
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.True. As would any other.
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.How do you feel about "hang indefinitely" (cancellation) and "corrupt program state" (termination)?
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.
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."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".
*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 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.I'm not sure what you mean by that. Almost any template function places burdens regarding exceptions on the types you give it.
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 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.I think the problem has been blown way out of proportion.
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
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.