Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #79975 > unrolled thread
| Started by | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| First post | 2021-05-26 11:51 +0000 |
| Last post | 2021-05-26 18:02 +0200 |
| Articles | 14 — 8 participants |
Back to article view | Back to comp.lang.c++
std::thread does not follow RAII principles Juha Nieminen <nospam@thanks.invalid> - 2021-05-26 11:51 +0000
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 14:04 +0200
Re: std::thread does not follow RAII principles MrSpook__u_8@_4fk8arybb76.eu - 2021-05-26 15:25 +0000
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 17:50 +0200
Re: std::thread does not follow RAII principles Paavo Helde <myfirstname@osa.pri.ee> - 2021-05-26 17:35 +0300
Re: std::thread does not follow RAII principles Manfred <noname@add.invalid> - 2021-05-26 17:44 +0200
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 17:52 +0200
Re: std::thread does not follow RAII principles Paavo Helde <myfirstname@osa.pri.ee> - 2021-05-26 21:41 +0300
Re: std::thread does not follow RAII principles scott@slp53.sl.home (Scott Lurndal) - 2021-05-26 15:20 +0000
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 17:54 +0200
Re: std::thread does not follow RAII principles MrSpook_c7o6A5w1@9wp2.net - 2021-05-26 16:28 +0000
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 19:04 +0200
Re: std::thread does not follow RAII principles MrSpook_0crgrbi6@q0jfxa33c.biz - 2021-05-26 15:24 +0000
Re: std::thread does not follow RAII principles Bonita Montero <Bonita.Montero@gmail.com> - 2021-05-26 18:02 +0200
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2021-05-26 11:51 +0000 |
| Subject | std::thread does not follow RAII principles |
| Message-ID | <s8lcnq$p2a$1@gioia.aioe.org> |
I have noticed a rather odd, and somewhat annoying, design decision in
std::thread, which breaks RAII design.
Normally when you use a C++ class from the standard library which allocates
some resource, the class in question will make sure to properly freeing
that resource when the object is destroyed, which is par for the course in
good RAII design.
For example, rather obviously, if you create an object of type std::vector,
it will delete its allocated memory (and destroy the elements) when it's
itself destroyed.
A more noteworthy example of something that allocates a resource other than
memory is std::ofstream: When it's destroyed, if it has a file open, it will
properly close the file.
This adds safety because it minimizes the risk of mistakes, especially since
functions may be exited at surprising places thanks to exceptions. Like:
void foo()
{
std::ofstream os("somefile");
doSomething(); // this might throw!
// ...
}
No matter how that function is exited, even if an exception is thrown,
that std::ofstream object will close the file so that the file handle isn't
leaked.
But now we come to std::thread. Suppose you have something like:
void foo()
{
std::thread t(someFunction);
doSomething();
signalTheThreadToStop();
t.join();
}
The problem with this is that if doSomething() throws an exception, the
program will crash. It doesn't even matter that you may be prepared for
the exception, like:
try { foo(); }
catch(...) { std::cout << "Exception thrown!\n"; }
the program will still crash, because std::thread does not like being
destroyed without being joined or detached, so it just terminates if that's
the case.
This is quite inconvenient, and as far as I know the standard library doesn't
really offer any utility to make disposing of the thread properly more
automatic. You'll have to write your own "thread handler" that will terminate
the thread properly when the thread object is destroyed, so that the
program won't crash if the function is exited unexpectedly.
This feels very counter to RAII principles, where objects should take care
of the resources they have allocated, rather than demanding the calling code
to manually do so.
[toc] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 14:04 +0200 |
| Message-ID | <s8ldgr$aq0$1@dont-email.me> |
| In reply to | #79975 |
> the program will still crash, because std::thread does not like being
> destroyed without being joined or detached, so it just terminates if that's
> the case.
Where's the problem ? Use a scrope-guard which waits for the end of the
thread or a jthread with C++.
That's my scope-guard class:
#pragma once
#include <cassert>
#include "debug_exceptions.h"
template<typename T>
struct invoke_on_destruct
{
private:
T m_t;
bool m_enabled;
public:
invoke_on_destruct( T t ) :
m_t( t ), m_enabled( true )
{
}
~invoke_on_destruct()
{
if( m_enabled )
{
try_debug
{
m_t();
}
catch_debug
{
assert(false);
}
}
}
void disable_and_invoke()
{
m_enabled = false;
m_t();
}
void disable()
{
m_enabled = false;
}
void enable()
{
m_enabled = true;
}
};
#if defined(IOD_SHORT)
template<typename C>
using iod = invoke_on_destruct<C>;
#define IOD(varName, lambdaName) \
iod<decltype(lambdaName)> varName( lambdaName );
#endif
[toc] | [prev] | [next] | [standalone]
| From | MrSpook__u_8@_4fk8arybb76.eu |
|---|---|
| Date | 2021-05-26 15:25 +0000 |
| Message-ID | <s8lp9t$1bmt$1@gioia.aioe.org> |
| In reply to | #79976 |
On Wed, 26 May 2021 14:04:42 +0200 Bonita Montero <Bonita.Montero@gmail.com> wrote: >> the program will still crash, because std::thread does not like being >> destroyed without being joined or detached, so it just terminates if that's >> the case. > >Where's the problem ? Use a scrope-guard which waits for the end of the >thread or a jthread with C++. > >That's my scope-guard class: This sort of home brew stuff shouldn't needed to control standard operations on threads.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 17:50 +0200 |
| Message-ID | <s8lqo4$9o4$1@dont-email.me> |
| In reply to | #79984 |
>>> the program will still crash, because std::thread does not like being
>>> destroyed without being joined or detached, so it just terminates if that's
>>> the case.
>> Where's the problem ? Use a scrope-guard which waits for the end of the
>> thread or a jthread with C++.
>> That's my scope-guard class:
> This sort of home brew stuff shouldn't needed to control standard operations
> on threads.
Why not ? Before C++20 there's no jthread, so you could write:
#define(IOD_SHORT)
#include <invoke_on_destruct.h>
...
{
thread thr( xxx );
auto waitForTerminate = [&]()
{
thr.join();
};
IOD(iodWaitForTerminate, waitForTerminate);
}
There's nothing unprofessional with that. I use IOD often,
especially for closing for closing resources for which it
would be too much work to have a special RAII-class for.
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2021-05-26 17:35 +0300 |
| Message-ID | <s8lmb5$7v8$1@dont-email.me> |
| In reply to | #79975 |
26.05.2021 14:51 Juha Nieminen kirjutas: > I have noticed a rather odd, and somewhat annoying, design decision in > std::thread, which breaks RAII design. > > the program will still crash, because std::thread does not like being > destroyed without being joined or detached, so it just terminates if that's > the case. std::thread is based on boost::thread which automatically detaches in the destructor. Alas, this would create a rampant thread which cannot be joined any more. I guess when it got standardized, they felt that such automatic detach is no good, but did not dare to enforce automatic join either, by some reason. So they chose to std::terminate() which is the worst of them all IMO. See https://isocpp.org/files/papers/p0206r0.html (Discussion about std::thread and RAII).
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-05-26 17:44 +0200 |
| Message-ID | <s8lqdp$16h$1@gioia.aioe.org> |
| In reply to | #79981 |
On 5/26/2021 4:35 PM, Paavo Helde wrote: > 26.05.2021 14:51 Juha Nieminen kirjutas: >> I have noticed a rather odd, and somewhat annoying, design decision in >> std::thread, which breaks RAII design. > >> >> the program will still crash, because std::thread does not like being >> destroyed without being joined or detached, so it just terminates if >> that's >> the case. > > std::thread is based on boost::thread which automatically detaches in > the destructor. Alas, this would create a rampant thread which cannot be > joined any more. > > I guess when it got standardized, they felt that such automatic detach > is no good, but did not dare to enforce automatic join either, by some > reason. So they chose to std::terminate() which is the worst of them all > IMO. > > See https://isocpp.org/files/papers/p0206r0.html (Discussion about > std::thread and RAII). Having the thread to detach on destruction is a poor choice, IMO. On the other hand defaulting to join would lead to buggy programs likely to hang indefinitely instead of recovering or terminate. I can understand the committee's concerns in this sense. We see more and more commonly (admittedly in mediocre programs) that unexpected default actions provided by "easy to use" languages bubble up to the level of user's experience because of software bugs - this reflects poorly on the perceived quality of the language itself. However, I agree with the OP that this is inconsistent with RAII principles. Thanks for the link, btw.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 17:52 +0200 |
| Message-ID | <s8lqr7$9o4$2@dont-email.me> |
| In reply to | #79981 |
> std::thread is based on boost::thread which automatically detaches in > the destructor. ... No, if the thread doesn't terminate before destruction or you detach it an exception is thrown and if that is done while un- winding your application is terminate()d.
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2021-05-26 21:41 +0300 |
| Message-ID | <s8m4p4$lqj$1@dont-email.me> |
| In reply to | #79989 |
26.05.2021 18:52 Bonita Montero kirjutas: >> std::thread is based on boost::thread which automatically detaches in >> the destructor. ... > > No, if the thread doesn't terminate before destruction or you > detach it an exception is thrown and if that is done while un- > winding your application is terminate()d. Right, it seems boost has formally deprecated the earlier detach() behavior in newer releases in favor of terminate(). This is controlled by the BOOST_THREAD_VERSION macro. By default this appears still to be defined to 2, which means detach(), and version 3 only appeared in 2012. So I should have said: "std::thread is based on boost::thread which automatically detached in the destructor, at least at the time when std::thread was standardized."
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2021-05-26 15:20 +0000 |
| Message-ID | <CGtrI.183233$gq3.41312@fx04.iad> |
| In reply to | #79975 |
Juha Nieminen <nospam@thanks.invalid> writes: >I have noticed a rather odd, and somewhat annoying, design decision in >std::thread, which breaks RAII design. That's one of the reasons we use pthreads instead of C++ threads.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 17:54 +0200 |
| Message-ID | <s8lquu$9o4$3@dont-email.me> |
| In reply to | #79982 |
> That's one of the reasons we use pthreads instead of C++ threads. pthreads are really poor. F.e. having the opportunity to pass arbitrary parameter lists which might hold resources as elegant as a shared_ptr<> is much more powerful. And if you use pthreads you could also use std::thread( xxx, params ... ).detach() instead.
[toc] | [prev] | [next] | [standalone]
| From | MrSpook_c7o6A5w1@9wp2.net |
|---|---|
| Date | 2021-05-26 16:28 +0000 |
| Message-ID | <s8lsul$1fkg$1@gioia.aioe.org> |
| In reply to | #79990 |
On Wed, 26 May 2021 17:54:06 +0200 Bonita Montero <Bonita.Montero@gmail.com> wrote: >> That's one of the reasons we use pthreads instead of C++ threads. > >pthreads are really poor. F.e. having the opportunity to pass Really? Want to have a guess what the C++ threading library on Linux uses?
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 19:04 +0200 |
| Message-ID | <s8lv3o$9rp$2@dont-email.me> |
| In reply to | #79998 |
>> pthreads are really poor. F.e. having the opportunity to pass > Really? Want to have a guess what the C++ threading library on Linux uses? We don't discuss physical threading but how the language presents threading; and C++11-threading is by far more convenient than pure pthreads.
[toc] | [prev] | [next] | [standalone]
| From | MrSpook_0crgrbi6@q0jfxa33c.biz |
|---|---|
| Date | 2021-05-26 15:24 +0000 |
| Message-ID | <s8lp80$1b4j$1@gioia.aioe.org> |
| In reply to | #79975 |
On Wed, 26 May 2021 11:51:24 +0000 (UTC) Juha Nieminen <nospam@thanks.invalid> wrote: >the program will still crash, because std::thread does not like being >destroyed without being joined or detached, so it just terminates if that's >the case. I'll have to add this to my list of why the C++ threading library is crap. I would suggest if your code doesn't need to be portable to either use posix threads on *nix or its Windows equivalent.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2021-05-26 18:02 +0200 |
| Message-ID | <s8lrec$fci$1@dont-email.me> |
| In reply to | #79983 |
> I'll have to add this to my list of why the C++ threading library is crap. Because of that ting ascpect ? Have you ever noticed the RAII-flexi- bility of C++-locking ? Have syou ever noted how convenient it is to pass arbitrary parameter-lists to your thread as it it would be a directly called function; compare the work of defining a structure, to define it, allocate it, fill it, pass it to the thread and deallo- cate it at the end of the thread - that's all for free in C++ and the performance is the same ! > I would suggest if your code doesn't need to be portable to > either use posix threads on *nix or its Windows equivalent. That's a lot of work more than with C++-threads.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web