Topic: Alternative to N4348: std::critical_section


Author: David Krauss <potswa@mac.com>
Date: Sun, 17 May 2015 16:52:48 +0800
Raw View
--Apple-Mail=_040C7C60-A513-436F-AC35-9D6861AC0352
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8


> On 2015=E2=80=9305=E2=80=9317, at 1:29 PM, Ville Voutilainen <ville.vouti=
lainen@gmail.com> wrote:
>=20
> That paper hasn't been discussed yet. As far as I understand, it will
> be revisited
> in Kona. I can't make any real predictions on it, but I can
> for-full-disclosure say
> that there is heavy opposition to that proposal due to compatibility issu=
es.
> And in case that wasn't clear, I will be raising such opposition.

Seems to me, the obvious solution would be to opt-in to synchronization thr=
ough functor adaptor classes.

There was a =E2=80=9Cdon=E2=80=99t add internal synchronization=E2=80=9D de=
cision <https://issues.isocpp.org/show_bug.cgi?id=3D34>. But an adaptor wou=
ld only be used to fix the specific problem, outside std::function.

Only a small minority of std::functions with non-const call operators actua=
lly ever face a race condition. They can be internally synchronized, but 99=
..9% just aren=E2=80=99t shared across threads. Existing data races in the w=
ild won=E2=80=99t be fixed by an opt-in. But fixing races in the wild witho=
ut massive breakage is rather a tall order in general.

Ville, what do you think? Is there really an imperative to fix concurrency =
within std::function itself, or would the motivation of N4348 apply here? S=
ee implementation below.


#include <mutex>

// Library proposal:

template< typename ftor, typename mutex >
class basic_critical_section {
    ftor f;
    mutable mutex m;
public:
    basic_critical_section( ftor in )
        : f( std::move( in ) ) {}

    basic_critical_section( basic_critical_section const & o )
        : f( [&o] {
            std::lock_guard< mutex > g( o.m );
            return o.f; // Return by value. Accomplish the copy before the =
lock is released.
        }() )
        {}

    basic_critical_section( basic_critical_section && o )
        : f( [&o] {
            std::lock_guard< mutex > g( o.m );
            return std::move( o.f );
        }() )
        {}

    template< typename ... arg >
    decltype(auto) operator () ( arg && ... a ) {
        std::lock_guard< mutex > g( m );
        return f( std::forward< arg >( a ) ... );
    }
};

template< typename ftor >
using critical_section =3D basic_critical_section< ftor, std::mutex >;

template< typename ftor >
using recursive_critical_section =3D basic_critical_section< ftor, std::rec=
ursive_mutex >;

// TODO: make_critical_section() factory.


// Demo:

#include <thread>
#include <atomic>
#include <unistd.h>
#include <iostream>

std::atomic< int > cnt;
thread_local int const tid =3D cnt ++;

int main() {
    auto fn =3D [] { std::cout << tid << '\n'; ::sleep( 1 ); };
    critical_section< decltype(fn) > cs( std::move( fn ) );
    std::function< void() > f =3D cs;

    for ( int i =3D 0; i !=3D 3; ++ i ) {
        new std::thread( [&] { for (;;) { f(); } } );
    }

    ::sleep( 10 );
    std::exit(0);
}

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

--Apple-Mail=_040C7C60-A513-436F-AC35-9D6861AC0352
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8

<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dutf-8"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: s=
pace; -webkit-line-break: after-white-space;" class=3D""><br class=3D""><di=
v><blockquote type=3D"cite" class=3D""><div class=3D"">On 2015=E2=80=9305=
=E2=80=9317, at 1:29 PM, Ville Voutilainen &lt;<a href=3D"mailto:ville.vout=
ilainen@gmail.com" class=3D"">ville.voutilainen@gmail.com</a>&gt; wrote:</d=
iv><br class=3D"Apple-interchange-newline"><div class=3D"">That paper hasn'=
t been discussed yet. As far as I understand, it will<br class=3D"">be revi=
sited<br class=3D"">in Kona. I can't make any real predictions on it, but I=
 can<br class=3D"">for-full-disclosure say<br class=3D"">that there is heav=
y opposition to that proposal due to compatibility issues.<br class=3D"">An=
d in case that wasn't clear, I will be raising such opposition.<br class=3D=
""></div></blockquote></div><br class=3D""><div class=3D"">Seems to me, the=
 obvious solution would be to opt-in to synchronization through functor ada=
ptor classes.</div><div class=3D""><br class=3D""></div><div class=3D"">The=
re was a =E2=80=9Cdon=E2=80=99t add internal synchronization=E2=80=9D&nbsp;=
<a href=3D"https://issues.isocpp.org/show_bug.cgi?id=3D34" class=3D"">decis=
ion</a>. But an adaptor would only be used to fix the specific problem,&nbs=
p;outside&nbsp;<font face=3D"Courier" class=3D"">std::function</font>.</div=
><div class=3D""><br class=3D""></div><div class=3D"">Only a small minority=
 of <font face=3D"Courier" class=3D"">std::function</font>s with non-const =
call operators actually ever face a race condition. They can be internally =
synchronized, but 99.9% just aren=E2=80=99t shared across threads. Existing=
 data races in the wild won=E2=80=99t be fixed by an opt-in. But fixing rac=
es in the wild without massive breakage is rather a tall order in general.<=
/div><div class=3D""><br class=3D""></div><div class=3D"">Ville, what do yo=
u think? Is there really an imperative to fix concurrency within <font face=
=3D"Courier" class=3D"">std::function</font> itself, or would the motivatio=
n of N4348 apply here? See implementation below.</div><div class=3D""><br c=
lass=3D""></div><div class=3D""><br class=3D""></div><div class=3D""><font =
face=3D"Courier" class=3D"">#include &lt;mutex&gt;<br class=3D""><br class=
=3D"">// Library proposal:</font></div><div class=3D""><font face=3D"Courie=
r" class=3D""><br class=3D""></font></div><div class=3D""><font face=3D"Cou=
rier" class=3D"">template&lt; typename ftor, typename mutex &gt;<br class=
=3D"">class basic_critical_section {<br class=3D"">&nbsp; &nbsp;&nbsp;ftor =
f;<br class=3D"">&nbsp; &nbsp;&nbsp;mutable mutex m;<br class=3D"">public:<=
br class=3D"">&nbsp; &nbsp;&nbsp;basic_critical_section( ftor in )<br class=
=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;: f( std::move( in ) ) {}<br class=
=3D""><br class=3D"">&nbsp; &nbsp;&nbsp;basic_critical_section( basic_criti=
cal_section const &amp; o )<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;=
: f( [&amp;o] {<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbs=
p;std::lock_guard&lt; mutex &gt; g( o.m );<br class=3D"">&nbsp; &nbsp; &nbs=
p; &nbsp; &nbsp; &nbsp;&nbsp;return o.f; // Return by value. Accomplish the=
 copy before the lock is released.<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp=
;&nbsp;}() )<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;{}<br class=3D"=
"><br class=3D"">&nbsp; &nbsp;&nbsp;basic_critical_section( basic_critical_=
section &amp;&amp; o )<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;: f( =
[&amp;o] {<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std=
::lock_guard&lt; mutex &gt; g( o.m );<br class=3D"">&nbsp; &nbsp; &nbsp; &n=
bsp; &nbsp; &nbsp;&nbsp;return std::move( o.f );<br class=3D"">&nbsp; &nbsp=
; &nbsp; &nbsp;&nbsp;}() )<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;{=
}<br class=3D""><br class=3D"">&nbsp; &nbsp;&nbsp;template&lt; typename ...=
 arg &gt;<br class=3D"">&nbsp; &nbsp;&nbsp;decltype(auto) operator () ( arg=
 &amp;&amp; ... a ) {<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;std::l=
ock_guard&lt; mutex &gt; g( m );<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&=
nbsp;return f( std::forward&lt; arg &gt;( a ) ... );<br class=3D"">&nbsp; &=
nbsp;&nbsp;}<br class=3D"">};<br class=3D""><br class=3D"">template&lt; typ=
ename ftor &gt;<br class=3D"">using critical_section =3D basic_critical_sec=
tion&lt; ftor, std::mutex &gt;;<br class=3D""><br class=3D"">template&lt; t=
ypename ftor &gt;<br class=3D"">using recursive_critical_section =3D basic_=
critical_section&lt; ftor, std::recursive_mutex &gt;;<br class=3D""><br cla=
ss=3D"">// TODO: make_critical_section() factory.<br class=3D""><br class=
=3D""><br class=3D"">// Demo:<br class=3D""><br class=3D""></font><span sty=
le=3D"font-family: Courier;" class=3D"">#include &lt;thread&gt;</span><br s=
tyle=3D"font-family: Courier;" class=3D""><span style=3D"font-family: Couri=
er;" class=3D"">#include &lt;atomic&gt;</span><br style=3D"font-family: Cou=
rier;" class=3D""><font face=3D"Courier" class=3D"">#include &lt;unistd.h&g=
t;<br class=3D"">#include &lt;iostream&gt;<br class=3D""><br class=3D"">std=
::atomic&lt; int &gt; cnt;<br class=3D"">thread_local int const tid =3D cnt=
 ++;<br class=3D""><br class=3D"">int main() {<br class=3D"">&nbsp; &nbsp;&=
nbsp;auto fn =3D [] { std::cout &lt;&lt; tid &lt;&lt; '\n'; ::sleep( 1 ); }=
;<br class=3D"">&nbsp; &nbsp;&nbsp;critical_section&lt; decltype(fn) &gt; c=
s( std::move( fn ) );<br class=3D"">&nbsp; &nbsp;&nbsp;std::function&lt; vo=
id() &gt; f =3D cs;<br class=3D""><br class=3D"">&nbsp; &nbsp;&nbsp;for ( i=
nt i =3D 0; i !=3D 3; ++ i ) {<br class=3D"">&nbsp; &nbsp; &nbsp; &nbsp;&nb=
sp;new std::thread( [&amp;] { for (;;) { f(); } } );<br class=3D"">&nbsp; &=
nbsp;&nbsp;}<br class=3D""><br class=3D"">&nbsp; &nbsp;&nbsp;::sleep( 10 );=
<br class=3D"">&nbsp; &nbsp;&nbsp;std::exit(0);<br class=3D"">}<br class=3D=
""></font></div></body></html>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--Apple-Mail=_040C7C60-A513-436F-AC35-9D6861AC0352--

.