Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #79975 > unrolled thread

std::thread does not follow RAII principles

Started byJuha Nieminen <nospam@thanks.invalid>
First post2021-05-26 11:51 +0000
Last post2021-05-26 18:02 +0200
Articles 14 — 8 participants

Back to article view | Back to comp.lang.c++


Contents

  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

#79975 — std::thread does not follow RAII principles

FromJuha Nieminen <nospam@thanks.invalid>
Date2021-05-26 11:51 +0000
Subjectstd::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]


#79976

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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]


#79984

FromMrSpook__u_8@_4fk8arybb76.eu
Date2021-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]


#79988

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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]


#79981

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-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]


#79986

FromManfred <noname@add.invalid>
Date2021-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]


#79989

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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]


#80007

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-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]


#79982

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-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]


#79990

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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]


#79998

FromMrSpook_c7o6A5w1@9wp2.net
Date2021-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]


#80001

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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]


#79983

FromMrSpook_0crgrbi6@q0jfxa33c.biz
Date2021-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]


#79994

FromBonita Montero <Bonita.Montero@gmail.com>
Date2021-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